MemPalace/mempalace · error · UnsupportedCapabilityError

facet_counts does not support local-only filters

Error message

facet_counts does not support local-only filters

What it means

facet_counts() on the pgvector backend translates the where filter into SQL. Some filter shapes (per _requires_local_filter) cannot be expressed in SQL pushdown and would need row-by-row local evaluation, which facet counting does not implement — so it raises UnsupportedCapabilityError. Validation happens before the unmaterialized-table short-circuit, so the error fires consistently even for empty collections.

Source

Thrown at mempalace/backends/pgvector.py:1234

            if self._marker_exists():
                raise CollectionNotInitializedError(self._collection_name)
            return 0
        return self._client.count_rows(self._table)

    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 even on an unmaterialized
        # collection — matches the order used by get()/lexical_search() and
        # qdrant.facet_counts (PR #1868 review).
        _validate_where(where)
        if _requires_local_filter(where):
            raise UnsupportedCapabilityError("facet_counts does not support local-only filters")
        if not self._table_exists():
            if self._marker_exists():
                raise CollectionNotInitializedError(self._collection_name)
            return {}
        return self._client.facet_counts(self._table, field=field, where=where, limit=limit)

    def lexical_search(self, *, query: str, n_results: int = 10, where: Optional[dict] = None):
        _validate_where(where)
        pushdown = None if _requires_local_filter(where) else where
        rows = self._scroll(where=pushdown, with_embedding=False)
        rows = [row for row in rows if _matches_where(row["metadata"], where)]
        scores = _bm25_scores(query, [row["document"] for row in rows])
        hits = [
            LexicalHit(
                id=row["id"],
                document=row["document"],
                metadata=row["metadata"],
                score=score,

View on GitHub (pinned to 06cb6987f0)

Solutions

  1. Simplify the filter to operators pgvector can push down (equality, $and/$or of simple clauses).
  2. Compute facet counts client-side: scroll/get the filtered rows and count field values in Python.
  3. Catch UnsupportedCapabilityError and degrade to a client-side aggregation path.

Example fix

# before
counts = col.facet_counts(field="room", where={"tags": {"$in": ["a", "b"]}})

# after
rows = col.get(where={"tags": {"$in": ["a", "b"]}}, include=["metadatas"])
counts = Counter(r["room"] for r in rows["metadatas"])
Defensive patterns

Strategy: fallback

Validate before calling

# only pushdown-safe filters: equality + $and/$or
safe = all(not isinstance(v, dict) or set(v) <= {"$eq"} for v in where.values()) if where else True
counts = col.facet_counts(field=f, where=where) if safe else client_side_facets(col, f, where)

Type guard

def is_pushdown_safe(where: dict) -> bool:
    return not _requires_local_filter(where)  # if importable; else whitelist operators

Try / catch

try:
    counts = col.facet_counts(field="room", where=filters)
except UnsupportedCapabilityError:
    rows = col.get(where=filters, include=["metadatas"])
    counts = Counter(r["room"] for r in rows["metadatas"])

Prevention

When it happens

Trigger: Calling facet_counts(field="room", where={"tags": {"$in": ["a","b"]}}) or any filter containing operators/shapes flagged as local-only by _requires_local_filter.

Common situations: Reusing a complex filter that worked for query() (which falls back to _query_local_exact) on facet_counts(); generic facet widgets that let users build arbitrary ChromaDB-style filters.

Related errors


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