Skip to content

[BUG] operandToRank silently substitutes Val(0) for nil operand #499

@tazarov

Description

@tazarov

Summary

operandToRank at pkg/api/v2/rank.go:1230-1233 silently substitutes Val(0) when called with a nil Operand:

func operandToRank(operand Operand) Rank {
    if operand == nil {
        return Val(0)
    }
    ...
}

This means that any programmer error like:

rrf.Add(nil)
rrf.Multiply(nil)
rrf.Sub(nil)

is silently turned into rrf + 0, rrf * 0, rrf - 0 — the query runs, the search returns results, and the only signal that something is wrong is the mathematically-transformed score.

Impact

  • All 10 RrfRank.* arithmetic methods fixed in Phase 21 are now affected by this footgun (they were previously no-ops, so the nil case was harmless).
  • Every other *Rank type that calls operandToRank (KnnRank, ValRank, SumRank, SubRank, MulRank, DivRank, AbsRank, ExpRank, LogRank, MaxRank, MinRank) has the same exposure.

Proposed Fix

Prefer the UnknownRank pattern already used in the default branch (rank.go:1244) — return &UnknownRank{} for nil as well. UnknownRank.MarshalJSON at rank.go:85 already fails loud with a clear error message:

UnknownRank: cannot marshal unknown operand type - this indicates a programming error

This converts a silent runtime footgun into a loud serialization-time failure that the caller can act on.

Alternative

Add a nil-check at each method entry point and return a rank with a deferred error (the error-returning pattern already used elsewhere in the package).

Discovery

Flagged during PR review of #496 by the silent-failure-hunter agent.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions