Skip to content

fix(query): stop sending HNSW params for an unhandled index type (#216) - #243

Merged
s2x merged 1 commit into
mainfrom
fix/216-diskann-ensure-params
Sep 29, 2026
Merged

s2x merged 1 commit into
mainfrom
fix/216-diskann-ensure-params

Conversation

@s2x

@s2x s2x commented Sep 29, 2026

Copy link
Copy Markdown
Member

Closes #216.

Summary

setRadius(), setLinear() and setUsingRefiner() all failed on a DiskANN field:

ZVecException code=3 Invalid query: query params type does not match the index
type of vector field[v], expected DISKANN but got HNSW

The message blames HNSW. The adapter was the one sending HNSW params.

Root cause

ensure_query_params_for_field() had no IndexType::DISKANN case and fell through to a hardcoded HNSW fallback. The fallback ran even when the index type had been resolved from the schema, so it silently converted "I do not handle this index type" into "these are HNSW params" — which upstream then rejects.

The only workaround was setDiskAnnParams() first, which is not discoverable from the error.

before:  radius → ERROR expected DISKANN but got HNSW
after:   radius only:     doc1,doc2        (doc3 is at L2² 2.0, correctly excluded)
         linear only:     doc1,doc2,doc3
         explicit+radius: doc1,doc2        (the old workaround still works)
         refiner:         upstream error   (was: the type mismatch)

Radius and linear are supported by the DiskANN core upstream — they were broken purely by the wrong param type. The refiner is a genuine upstream limitation, but it now reports upstream's own error instead of blaming the wrong thing.

DiskAnnQueryParams only takes list_size in its constructor, so radius and the flags are set afterwards from the common QueryParams base.

The more valuable half

The default: branch no longer falls back to HNSW at all. An index type with no case now gets no query params, which lets upstream use its own defaults and skip its params-type check:

  • fails far less often than guessing
  • also covers index types added upstream after this adapter was written — DiskANN and IVF_RABITQ were both missing for exactly this reason

The trade-off is that radius/linear/refiner are not applied in that case, so each new index type needs its own branch. That is recorded in the comment rather than left for the next person to rediscover. The group-by switch had the same fallback and got the same treatment.

Verification

tests/bug_0057.phpt covers the three cases plus the refiner. Since the removed fallback was silently doing work for the unresolvable case, I also checked that the handled types still filter correctly:

hnsw   : d1
ivf    : d1
flat   : d1
vamana : d1

Full suite:

Number of tests : 213               213
Tests skipped   :   0 (  0.0%)
Tests failed    :   0 (  0.0%)
Tests passed    : 211 ( 99.1%)

One test-hygiene note: the refiner case is expected to fail and upstream logs it at ERROR on stderr, so the test initialises with LOG_FATAL — same reason the FTS tokenizer tests do.

🤖 Generated with Claude Code

setRadius(), setLinear() and setUsingRefiner() all failed on a DiskANN
field with

    query params type does not match the index type of vector field[v],
    expected DISKANN but got HNSW

The message blamed HNSW, but the adapter was the one sending HNSW params.

ensure_query_params_for_field() had no IndexType::DISKANN case, so it
fell through to a hardcoded HNSW fallback. The fallback ran even when the
index type *had* been resolved from the schema, so it silently converted
"I do not handle this index type" into "these are HNSW params" -- and
upstream rejects exactly that. The workaround was to call
setDiskAnnParams() first, which is not discoverable.

Radius and linear are supported by the DiskANN core upstream, so they
were broken purely by the wrong param type and now work. The refiner is an
upstream DiskANN limitation, but it now reports upstream's own error
instead of the misleading type mismatch.

DiskAnnQueryParams only takes list_size in its constructor, so radius and
the flags are set afterwards from the common QueryParams base.

The default: branch no longer falls back to HNSW at all. An index type
with no case now gets no query params, which lets upstream use its own
defaults and skip its params-type check. That fails far less often than
guessing, and it also covers index types added upstream after this
adapter was written -- the DiskANN and IVF_RABITQ cases were both
missing for the same reason. The trade-off is that radius/linear/refiner
are not applied in that case, so each new index type needs its own
branch; that is recorded in the comment. The group-by switch, which had
the same HNSW fallback, got the same treatment.

Test: tests/bug_0057.phpt. Verified separately that HNSW, IVF, Flat and
Vamana still filter by radius correctly, since the fallback was silently
doing work for the unresolvable case.

Tests: 213/213, 0 skipped, 0 failed, 2 expected fail.
@s2x
s2x merged commit b16e4a2 into main Sep 29, 2026
6 checks passed
@s2x
s2x deleted the fix/216-diskann-ensure-params branch September 29, 2026 13:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

fix: queryVector() with setRadius/setLinear/setUsingRefiner on a DiskANN field sends HNSW query params and fails

1 participant