{"record":{"id":"326c0cd422e86ea8","repo":"headroomlabs-ai/headroom","slug":"either-query-vector-or-query-text-must-be-provided","errorCode":null,"errorMessage":"Either query_vector or query_text must be provided","messagePattern":"Either query_vector or query_text must be provided","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"headroom/memory/adapters/hnsw.py","lineNumber":595,"sourceCode":"        \"\"\"Search for similar memories using vector similarity.\n\n        Args:\n            filter: Vector search filter with query and constraints.\n\n        Returns:\n            List of search results sorted by similarity (descending).\n\n        Raises:\n            ValueError: If neither query_vector nor query_text is provided,\n                       or if query_text is provided (embedding must be done externally).\n        \"\"\"\n        if filter.query_vector is None:\n            if filter.query_text is not None:\n                raise ValueError(\n                    \"query_text provided but HNSWVectorIndex does not embed text. \"\n                    \"Provide query_vector directly or use an Embedder first.\"\n                )\n            raise ValueError(\"Either query_vector or query_text must be provided\")\n\n        query_vector = np.asarray(filter.query_vector, dtype=np.float32)\n        if query_vector.shape[0] != self._dimension:\n            raise ValueError(\n                f\"Query vector dimension {query_vector.shape[0]} does not match \"\n                f\"index dimension {self._dimension}\"\n            )\n\n        with self._lock:\n            # NOTE: Use len() directly, not self.size - Lock is not reentrant!\n            current_size = len(self._memory_to_hnsw)\n            if current_size == 0:\n                return []\n\n            # Search with more results than needed to account for filtering\n            # Retrieve extra candidates to improve recall after filtering\n            k_with_buffer = min(\n                filter.top_k * 10,  # Get 10x candidates for filtering","sourceCodeStart":577,"sourceCodeEnd":613,"githubUrl":"https://github.com/headroomlabs-ai/headroom/blob/322425c43bffde1ed0b64fecf3cf5951565dd82b/headroom/memory/adapters/hnsw.py#L577-L613","documentation":"Raised by HNSWVectorIndex.search when the VectorFilter carries neither query_vector nor query_text. The search API requires at least one query representation; an empty filter is a caller bug rather than a valid 'match all' request.","triggerScenarios":"Constructing VectorFilter() with only constraint fields (user_id, session_id filters) and no query; a variable holding the query string ends up None and is assigned to query_text.","commonSituations":"Optional query parameters flowing from an API request defaulting to None; building filters dynamically where the query key is missing; expecting filter-only search semantics.","solutions":["Ensure either query_vector or query_text is populated before calling search.","If the query source can be None, validate at the API boundary and return a 400 instead of calling the index.","For listing without similarity, use the store's listing API, not vector search."],"exampleFix":"// before\nf = VectorFilter(user_id=\"u1\")  # no query at all\nresults = await index.search(f)\n\n// after\nif query is None:\n    raise HTTPException(400, \"query required\")\nresults = await index.search(VectorFilter(query_vector=await embedder.embed(query), user_id=\"u1\"))","handlingStrategy":"validation","validationCode":"if filter.query_vector is None and filter.query_text is None:\n    raise ValueError(\"Vector search requires a query\")\nresults = await index.search(filter)","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Validate queries at the API boundary before reaching the index.","Use listing APIs for constraint-only requests."],"tags":["hnsw","search","validation","missing-argument"],"backgroundTag":null,"analyzedSha":"322425c43bffde1ed0b64fecf3cf5951565dd82b","analyzedAt":"2026-08-15T01:03:05.481Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}