{"record":{"id":"58ca64ffb9303369","repo":"chroma-core/chroma","slug":"knn-requires-exactly-one-query-embedding","errorCode":null,"errorMessage":"$knn requires exactly one query embedding","messagePattern":"\\$knn requires exactly one query embedding","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"chromadb/execution/expression/operator.py","lineNumber":713,"sourceCode":"                raise ValueError(\"$knn requires 'query' field\")\n\n            query = knn_data[\"query\"]\n\n            if isinstance(query, dict):\n                # SparseVector case - deserialize from transport format\n                if query.get(TYPE_KEY) == SPARSE_VECTOR_TYPE_VALUE:\n                    query = SparseVector.from_dict(query)\n                else:\n                    # Old format or invalid - try to construct directly\n                    raise ValueError(\n                        f\"Expected dict with {TYPE_KEY}='{SPARSE_VECTOR_TYPE_VALUE}', got {query}\"\n                    )\n\n            elif isinstance(query, (list, tuple, np.ndarray)):\n                # Dense vector case - normalize then validate\n                normalized = normalize_embeddings(query)\n                if not normalized or len(normalized) > 1:\n                    raise ValueError(\"$knn requires exactly one query embedding\")\n\n                # Validate the normalized version\n                validate_embeddings(normalized)\n\n                query = normalized[0]\n\n            else:\n                raise TypeError(\n                    f\"$knn query must be a list, numpy array, or SparseVector dict, got {type(query).__name__}\"\n                )\n\n            key = knn_data.get(\"key\", \"#embedding\")\n            if not isinstance(key, str):\n                raise TypeError(f\"$knn key must be a string, got {type(key).__name__}\")\n\n            limit = knn_data.get(\"limit\", 16)\n            if not isinstance(limit, int):\n                raise TypeError(","sourceCodeStart":695,"sourceCodeEnd":731,"githubUrl":"https://github.com/chroma-core/chroma/blob/aecdd12c8a891610db8653630b066b32ceb678b5/chromadb/execution/expression/operator.py#L695-L731","documentation":"For a dense (list/tuple/ndarray) $knn query, the parser normalizes the input with normalize_embeddings() and requires exactly one embedding row: an empty sequence or multiple rows ([[...], [...]]) raises ValueError. Unlike collection.query(query_embeddings=[...]), the $knn rank operator scores a single query at a time.","triggerScenarios":"{'$knn': {'query': []}} (empty); {'$knn': {'query': [[0.1, 0.2], [0.3, 0.4]]}} (batch of 2); feeding an encoder's 2-D batched output directly as the query.","commonSituations":"Embedding models that always return 2-D arrays ([[...]]); porting collection.query(query_embeddings=[q1, q2]) call sites to Search; empty queries when the embedding service returned nothing.","solutions":["Pass exactly one flat vector [0.1, 0.2, ...] or a single row [[0.1, 0.2]].","Index into batched encoder output: emb = model.encode([text])[0].","Guard empty embeddings upstream - skip the search or raise your own error."],"exampleFix":"# before\nembs = model.encode(['a', 'b'])          # shape (2, d)\nSearch(rank={'$knn': {'query': embs}})    # -> ValueError\n\n# after\nSearch(rank={'$knn': {'query': embs[0]}})\n# or one text at a time\nSearch(rank={'$knn': {'query': model.encode([text])[0]}})","handlingStrategy":"validation","validationCode":"import numpy as np\n\ndef single_query_embedding(emb) -> list:\n    arr = np.asarray(emb, dtype=float)\n    if arr.ndim == 2:\n        if arr.shape[0] != 1:\n            raise ValueError(f'expected 1 query embedding, got {arr.shape[0]}')\n        arr = arr[0]\n    if arr.size == 0:\n        raise ValueError('query embedding is empty')\n    return arr.tolist()\n\nSearch(rank={'$knn': {'query': single_query_embedding(emb)}})","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Know your encoder's output shape - squeeze to 1-D before querying.","$knn is single-query by design; loop over batches at the caller.","Treat an empty embedding as a hard pipeline error, not an empty query."],"tags":["validation","valueerror","knn","embedding","batching","chromadb"],"backgroundTag":"embedding-shape-mismatch","analyzedSha":"aecdd12c8a891610db8653630b066b32ceb678b5","analyzedAt":"2026-08-16T21:53:27.228Z","schemaVersion":2},"datasetVersion":"2026-08-16T23:17:17.608Z"}