MemPalace/mempalace · warning · UnsupportedCapabilityError

facet_counts does not support local-only filters

Error message

facet_counts does not support local-only filters

What it means

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).

Source

Thrown at mempalace/backends/qdrant.py:1084

        dance inline.)
        """
        rows = self._rows(where=where)
        return [row["metadata"] for row in rows]

    def facet_counts(
        self,
        field: str,
        where: Optional[dict] = None,
        limit: int = 1000,
    ) -> dict[str, int]:
        self._ensure_open()
        # Validate the filter before the existence short-circuit so an
        # unsupported local-only filter raises regardless of whether the
        # collection has been materialized yet — matching the order used by
        # get()/lexical_search() above (#1835 review).
        _validate_where(where)
        if _requires_local_filter(where):
            raise UnsupportedCapabilityError("facet_counts does not support local-only filters")
        if not self._remote_exists():
            if self._marker_exists():
                raise CollectionNotInitializedError(self._collection_name)
            return {}

        q_filter = _qdrant_filter(where)

        return self._client.facet_counts(
            self._remote_collection,
            field=f"{_PAYLOAD_METADATA}.{field}",
            qdrant_filter=q_filter,
            limit=limit,
        )

    def delete(self, *, ids=None, where=None):
        _validate_where(where)
        if not self._remote_exists():
            if self._marker_exists():

View on GitHub (pinned to 06cb6987f0)

Solutions

  1. Simplify the filter to server-supported operators ($eq/$ne/$in etc. on plain metadata fields) so it translates to a Qdrant filter
  2. Compute facets client-side: get() with the filter (local fallback works there), then Counter() over the returned metadata field
  3. Split the filter: apply the server-translatable part to facet_counts and the local-only part when post-processing results
  4. Check _validate_where/_requires_local_filter in this file for the exact operator list that stays server-side

Example fix

# before
collection.facet_counts("wing", where={"$and": [{"room": {"$eq": "r1"}}, {"text": {"$contains": "x"}}]})  # local-only -> raises
// after
rows = collection.get(where={"$and": [{"room": {"$eq": "r1"}}, {"text": {"$contains": "x"}}]})
from collections import Counter
facets = Counter(m.get("wing") for m in rows.metadatas)
Defensive patterns

Strategy: fallback

Validate before calling

def server_side_where(where):
    # keep only operators the backend translates (e.g. $eq/$ne/$in on plain fields)
    return {k: v for k, v in where.items() if k in ("$eq", "$ne", "$in", "$and", "$or")} if where else None

Try / catch

from mempalace.backends.base import UnsupportedCapabilityError
try:
    facets = collection.facet_counts("wing", where=where)
except UnsupportedCapabilityError:
    rows = collection.get(where=where)  # local filter path works here
    from collections import Counter
    facets = Counter(m.get("wing") for m in rows.metadatas if m.get("wing") is not None)

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of MemPalace/mempalace@06cb6987f0 (2026-08-15). Data as JSON: /api/errors/fd833e3ea1f37bdf. Report an issue: GitHub.