Skip to content

fix(qdrant): prevent invalid filter nesting when using preFilters#2270

Open
serhiizghama wants to merge 1 commit intorun-llama:mainfrom
serhiizghama:fix/issue-2035-qdrant-prefilters-nesting
Open

fix(qdrant): prevent invalid filter nesting when using preFilters#2270
serhiizghama wants to merge 1 commit intorun-llama:mainfrom
serhiizghama:fix/issue-2035-qdrant-prefilters-nesting

Conversation

@serhiizghama
Copy link
Copy Markdown

Problem

Closes #2035

When using preFilters with QdrantVectorStore, all queries returned a 400 Bad Request from Qdrant. The root cause was in buildQueryFilter:

// Before — broken
const metadataFilters = toQdrantMetadataFilters(query.filters);
if (metadataFilters) {
  mustConditions.push(metadataFilters); // ← pushes {must:[...]} into must array
}
return { must: mustConditions };
// Produces: { must: [{ must: [...conditions] }] } — invalid Qdrant filter

toQdrantMetadataFilters() already returns a full QdrantFilter object ({must: [...]} or {should: [...]}). Pushing that into another must array creates one extra layer of nesting that the Qdrant REST API rejects.

What changed

packages/providers/storage/qdrant/src/QdrantVectorStore.ts

  • When no docIds are present, return metadataFilters directly instead of wrapping it
  • When both docIds and metadata filters exist, spread AND-condition filter conditions flat into mustConditions; keep OR-condition (should) filters as a nested filter object to preserve their semantics

packages/providers/storage/qdrant/tests/QdrantVectorStore.test.ts

  • Added test: filters-only AND — verifies filter is flat, no extra nesting
  • Added test: docId + metadata filters — verifies both conditions appear at the same must level
  • Added test: filters-only OR — verifies should array is produced at the top level

How to test

const queryEngine = index.asQueryEngine({
  preFilters: {
    filters: [{ key: 'projectId', value: 'my-id', operator: '==' }],
  },
});
const result = await queryEngine.query({ query: 'what is this?' });
// Should no longer throw 400 Bad Request

Or run the unit tests:

cd packages/providers/storage/qdrant && pnpm test

When query.filters are passed without docIds, buildQueryFilter was
wrapping toQdrantMetadataFilters() output inside an extra must array,
producing { must: [{ must: [...] }] } instead of the flat
{ must: [...] } that Qdrant expects. This caused 400 Bad Request errors
whenever preFilters were used with QdrantVectorStore.

Changes:
- Return metadataFilters directly when no docIds are present
- When docIds and metadata filters coexist, spread AND-condition filter
  conditions flat into mustConditions; keep OR-condition filters as a
  nested filter to preserve their semantics
- Add three tests covering: filters-only AND, docId+filters combined,
  and filters-only OR cases
@changeset-bot
Copy link
Copy Markdown

changeset-bot bot commented Mar 28, 2026

⚠️ No Changeset found

Latest commit: c3161fb

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@serhiizghama serhiizghama marked this pull request as ready for review March 29, 2026 13:11
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.

QdrantVectorStore preFilters causing 400 Bad Request error

1 participant