{"record":{"id":"fd833e3ea1f37bdf","repo":"MemPalace/mempalace","slug":"facet-counts-does-not-support-local-only-filters-fd833e","errorCode":null,"errorMessage":"facet_counts does not support local-only filters","messagePattern":"facet_counts does not support local-only filters","errorType":"validation","errorClass":"UnsupportedCapabilityError","httpStatus":null,"severity":"warning","filePath":"mempalace/backends/qdrant.py","lineNumber":1084,"sourceCode":"        dance inline.)\n        \"\"\"\n        rows = self._rows(where=where)\n        return [row[\"metadata\"] for row in rows]\n\n    def facet_counts(\n        self,\n        field: str,\n        where: Optional[dict] = None,\n        limit: int = 1000,\n    ) -> dict[str, int]:\n        self._ensure_open()\n        # Validate the filter before the existence short-circuit so an\n        # unsupported local-only filter raises regardless of whether the\n        # collection has been materialized yet — matching the order used by\n        # get()/lexical_search() above (#1835 review).\n        _validate_where(where)\n        if _requires_local_filter(where):\n            raise UnsupportedCapabilityError(\"facet_counts does not support local-only filters\")\n        if not self._remote_exists():\n            if self._marker_exists():\n                raise CollectionNotInitializedError(self._collection_name)\n            return {}\n\n        q_filter = _qdrant_filter(where)\n\n        return self._client.facet_counts(\n            self._remote_collection,\n            field=f\"{_PAYLOAD_METADATA}.{field}\",\n            qdrant_filter=q_filter,\n            limit=limit,\n        )\n\n    def delete(self, *, ids=None, where=None):\n        _validate_where(where)\n        if not self._remote_exists():\n            if self._marker_exists():","sourceCodeStart":1066,"sourceCodeEnd":1102,"githubUrl":"https://github.com/MemPalace/mempalace/blob/06cb6987f02610784fefbad4b2bd5d026d164ba6/mempalace/backends/qdrant.py#L1066-L1102","documentation":"Raised by QdrantCollection.facet_counts() when the where filter requires local-only post-filtering (operator/expression shapes the backend cannot translate to a Qdrant server-side filter). UnsupportedCapabilityError: facet counting must execute entirely server-side, so filters that normally fall back to local exact filtering in get()/query() cannot be honored here. Note the filter is validated before the existence short-circuit so the error raises deterministically (#1835 review).","triggerScenarios":"Passing a where clause containing operators this backend evaluates locally (e.g. $contains-style or nested expressions unsupported by _qdrant_filter) to facet_counts(), while the same filter works on get() via the local fallback path.","commonSituations":"Copy-pasting a complex filter from a search call into a facets/dashboard call; frontend facets UI reusing the search filter builder verbatim; version change where a filter shape moved from server-translatable to local-only.","solutions":["Simplify the filter to server-supported operators ($eq/$ne/$in etc. on plain metadata fields) so it translates to a Qdrant filter","Compute facets client-side: get() with the filter (local fallback works there), then Counter() over the returned metadata field","Split the filter: apply the server-translatable part to facet_counts and the local-only part when post-processing results","Check _validate_where/_requires_local_filter in this file for the exact operator list that stays server-side"],"exampleFix":"# before\ncollection.facet_counts(\"wing\", where={\"$and\": [{\"room\": {\"$eq\": \"r1\"}}, {\"text\": {\"$contains\": \"x\"}}]})  # local-only -> raises\n// after\nrows = collection.get(where={\"$and\": [{\"room\": {\"$eq\": \"r1\"}}, {\"text\": {\"$contains\": \"x\"}}]})\nfrom collections import Counter\nfacets = Counter(m.get(\"wing\") for m in rows.metadatas)","handlingStrategy":"fallback","validationCode":"def server_side_where(where):\n    # keep only operators the backend translates (e.g. $eq/$ne/$in on plain fields)\n    return {k: v for k, v in where.items() if k in (\"$eq\", \"$ne\", \"$in\", \"$and\", \"$or\")} if where else None","typeGuard":null,"tryCatchPattern":"from mempalace.backends.base import UnsupportedCapabilityError\ntry:\n    facets = collection.facet_counts(\"wing\", where=where)\nexcept UnsupportedCapabilityError:\n    rows = collection.get(where=where)  # local filter path works here\n    from collections import Counter\n    facets = Counter(m.get(\"wing\") for m in rows.metadatas if m.get(\"wing\") is not None)","preventionTips":["Keep facet filters simple (equality/$in) so they stay server-side","For dashboards with complex filters, plan a client-side Counter fallback from the start","Read _requires_local_filter to know exactly which filter shapes facet_counts rejects"],"tags":["filters","facets","qdrant","unsupported-feature"],"backgroundTag":null,"analyzedSha":"06cb6987f02610784fefbad4b2bd5d026d164ba6","analyzedAt":"2026-08-15T03:03:36.213Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}