Skip to content

bug: update_vectors returns early when first point doesn't match update_filter, skipping remaining points #1237

Description

@rtmalikian

Problem

In LocalCollection.update_vectors(), when processing a batch of points with an update_filter, if any point doesn't match the filter, the function executes return None (line 2649), which exits the entire function immediately. This causes all remaining points in the batch to be silently skipped.

Root Cause

# local_collection.py, line 2646-2649
if not check_filter(
    update_filter, self.payload[idx], self.ids_inv[idx], has_vector
):
    return None  # BUG: should be "continue"

return None exits the entire update_vectors method. It should be continue to skip only the current point and process the remaining ones.

Impact

When calling update_vectors with multiple points and an update_filter:

  • If point N doesn't match the filter, points N+1, N+2, ... are never updated
  • The caller gets None instead of UpdateResult, with no indication that points were skipped
  • This is a silent data loss bug — updates that should succeed are discarded

Steps to Reproduce

from qdrant_client import QdrantClient
from qdrant_client.models import VectorParams, Distance, PointStruct, PointVectors, Filter, FieldCondition, MatchValue

client = QdrantClient(path="/tmp/test_db")
client.create_collection("test", vectors_config=VectorParams(size=4, distance=Distance.COSINE))

# Insert 3 points
client.upsert("test", points=[
    PointStruct(id=1, vector=[1,0,0,0], payload={"type": "a"}),
    PointStruct(id=2, vector=[0,1,0,0], payload={"type": "b"}),
    PointStruct(id=3, vector=[0,0,1,0], payload={"type": "a"}),
])

# Update vectors with filter matching only type="a"
# Point 2 (type="b") doesn't match, so points 3 is also skipped
client.update_vectors("test", points=[
    PointVectors(id=1, vector=[0.5, 0.5, 0, 0]),
    PointVectors(id=2, vector=[0, 0, 0.5, 0.5]),  # doesn't match filter
    PointVectors(id=3, vector=[0, 0, 0, 1]),       # matches filter but gets skipped!
], update_filter=Filter(must=[FieldCondition(key="type", match=MatchValue(value="a"))]))

# Point 3 should have been updated but wasn't

Proposed Fix

Change return None to continue on line 2649:

if not check_filter(
    update_filter, self.payload[idx], self.ids_inv[idx], has_vector
):
    continue  # Skip this point, process the rest

Verification

After the fix, all points matching the filter should be updated regardless of their position in the batch.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions