Skip to content

RESP2 Null Array: Frame::Null always serialises as $-1, so BLPOP and friends reply the wrong type #482

Description

@TinDang97

Frame has no null-array variant, so every command whose empty answer is an array replies with the wrong RESP2 type.

Frame::Null serialises to $-1 (Null Bulk), full stop. Redis answers *-1 (Null Array) wherever the missing value is an array. A statically-typed client decodes the two differently, so this is a decode error on the client, not a cosmetic difference.

This is not a MULTI bug — it was found inside MULTI but reproduces on a plain connection:

BLPOP missing 1        # Moon: $-1     Redis: *-1

Measured inside a transaction (tests/multi_exec_queue_semantics.rs::me7):

Moon:  *1\r\n$-1\r\n
Redis: *1\r\n*-1\r\n

Why it was not fixed in #472

The fix is a Frame::NullArray variant threaded through the ~14 Frame::Null match arms in serialize.rs and resp3.rs. That touches every reply path in the server, so it needs its own contract and its own review rather than riding along inside a MULTI-semantics change. Getting it wrong flips the type of replies that are currently correct.

RESP3 is unaffected in the same way — _\r\n is the null for both shapes there — so the divergence is RESP2-only, which is also why it survived the RESP3 type-fidelity work.

Scope

  • add Frame::NullArray, serialising to *-1 in RESP2 and _\r\n in RESP3
  • audit every Frame::Null site and decide, per site, which null it means — the audit is the task; a blanket replace would be wrong in both directions
  • blocking commands' zero-timeout path (BLPOP, BRPOP, BLMOVE, BZPOPMIN/MAX) are the known callers, but the audit governs
  • un-ignore me7_blpop_in_multi_returns_null_array_not_null_bulk in tests/multi_exec_queue_semantics.rs — the assertion is already correct, only the capability is missing
  • add a compat-harness entry so the oracle keeps this honest

Provenance

Unmet Must #7 of the multi-exec-queue-semantics ADD task, whose gate is recorded RISK-ACCEPTED against this issue.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions