MemPalace/mempalace · error · UnsupportedFilterError

operator {k!r} not supported by chroma backend

Error message

operator {k!r} not supported by chroma backend

What it means

A MaxSeqIdVerificationError raised at the end of repair_max_seq_id: after applying the repair plan, re-running poisoned-row detection still finds rows above the threshold. The repair wrote changes but verification failed, meaning the fix did not take effect for all planned segments; a backup of the pre-repair state is referenced in the message.

Source

Thrown at mempalace/backends/chroma.py:279

# (don't attempt recovery on segments with negligible data).
_HNSW_MISSING_METADATA_DATA_FLOOR = 1024


def _validate_where(where: Optional[dict]) -> None:
    """Scan a where-clause for unknown operators and raise ``UnsupportedFilterError``.

    Spec (RFC 001 §1.4): silent dropping of unknown operators is forbidden.
    """
    if not where:
        return
    stack = [where]
    while stack:
        node = stack.pop()
        if not isinstance(node, dict):
            continue
        for k, v in node.items():
            if k.startswith("$") and k not in _SUPPORTED_OPERATORS:
                raise UnsupportedFilterError(f"operator {k!r} not supported by chroma backend")
            if isinstance(v, dict):
                stack.append(v)
            elif isinstance(v, list):
                stack.extend(x for x in v if isinstance(x, dict))


def _tokenize(text: str) -> list[str]:
    if not text:
        return []
    return _TOKEN_RE.findall(text.lower())


def _bm25_scores(
    query: str,
    documents: list[str],
    k1: float = 1.5,
    b: float = 0.75,
) -> list[float]:

View on GitHub (pinned to 06cb6987f0)

Solutions

  1. Stop all processes that touch the palace's chroma.sqlite3 (MCP server, mining hooks) and re-run the repair.
  2. Compare the remaining segment ids in the message against result['segment_repaired'] to see which segments were missed.
  3. If state looks wrong, restore from the backup path named in the message.
  4. Re-run detection with the same threshold/segment arguments used for the repair to rule out argument drift.
Defensive patterns

Strategy: retry

Validate before calling

from mempalace import repair
poisoned = repair._detect_poisoned_max_seq_ids(db_path, threshold=threshold)
if poisoned:
    ensure_no_live_chromadb_processes(palace_path)  # lsof/fuser check

Try / catch

try:
    repair_max_seq_id(palace_path, threshold=threshold)
except MaxSeqIdVerificationError as e:
    stop_palace_processes()
    repair_max_seq_id(palace_path, threshold=threshold)  # retry with DB quiescent

Prevention

When it happens

Trigger: The post-repair _detect_poisoned_max_seq_ids() call still returns rows — e.g. another process rewrote seq_ids between the UPDATE and the check, the plan missed segments, or the detection threshold/context differs between runs.

Common situations: Running the repair while chromadb (MCP server, miner) is live and rewriting the DB; concurrent repairs; a detection threshold passed differently on the retry.

Related errors


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