MemPalace/mempalace · error · UnsupportedFilterError
operator {key!r} not supported by sqlite_exact
Error message
operator {key!r} not supported by sqlite_exact What it means
Raised by sqlite_exact's pre-flight validation of a `where` filter. The backend walks every dict node of the filter and rejects any key starting with `$` that is not in `_SUPPORTED_OPERATORS`. It exists because this backend implements only a small Mongo-like operator subset and would otherwise silently mis-evaluate unknown operators.
Source
Thrown at mempalace/backends/sqlite_exact.py:147
for term, freq in tf.items():
num = freq * (k1 + 1)
den = freq + k1 * (1 - b + b * dl / avgdl)
score += float(idf[term]) * num / den
scores.append(score)
return scores
def _validate_where(where: Optional[dict]) -> None:
if not where:
return
stack = [where]
while stack:
node = stack.pop()
if not isinstance(node, dict):
continue
for key, value in node.items():
if key.startswith("$") and key not in _SUPPORTED_OPERATORS:
raise UnsupportedFilterError(f"operator {key!r} not supported by sqlite_exact")
if isinstance(value, dict):
stack.append(value)
elif isinstance(value, list):
stack.extend(item for item in value if isinstance(item, dict))
def _coerce_comparable(value: Any):
if isinstance(value, bool):
return int(value)
return value
def _compare(actual: Any, op: str, expected: Any) -> bool:
actual = _coerce_comparable(actual)
expected = _coerce_comparable(expected)
if op == "$eq":
return actual == expected
if op == "$ne":View on GitHub (pinned to 06cb6987f0)
Solutions
- Check `_SUPPORTED_OPERATORS` in mempalace/backends/sqlite_exact.py and rewrite the filter using only those operators (typically $and/$or/$gt/$gte/$lt/$lte/$ne/$eq/$in/$contains).
- Replace unsupported logical operators ($nor, $not) with $and/$or combinations of supported comparisons.
- Move exotic matching out of the backend: fetch with a broader supported filter and post-filter in Python.
- If you need richer filters, use the ChromaDB backend instead of sqlite_exact.
Example fix
# before
where = {"$nor": [{"status": "draft"}, {"status": "archived"}]}
col.get(where=where)
# after
where = {"$and": [{"status": {"$ne": "draft"}}, {"status": {"$ne": "archived"}}]}
col.get(where=where) Defensive patterns
Strategy: validation
Validate before calling
from mempalace.backends.sqlite_exact import _SUPPORTED_OPERATORS
def validate_where(where):
stack = [where]
while stack:
node = stack.pop()
if not isinstance(node, dict):
continue
for key, value in node.items():
if key.startswith("$") and key not in _SUPPORTED_OPERATORS:
raise ValueError(f"unsupported filter operator {key!r}; rewrite with {_SUPPORTED_OPERATORS}")
if isinstance(value, dict):
stack.append(value)
elif isinstance(value, list):
stack.extend(i for i in value if isinstance(i, dict))
return where Type guard
def is_supported_filter(where: dict) -> bool:
stack = [where]
while stack:
node = stack.pop()
if not isinstance(node, dict):
continue
for key, value in node.items():
if key.startswith("$") and key not in _SUPPORTED_OPERATORS:
return False
if isinstance(value, dict):
stack.append(value)
elif isinstance(value, list):
stack.extend(i for i in value if isinstance(i, dict))
return True Try / catch
try:
col.get(where=where)
except UnsupportedFilterError as e:
logger.warning("rewriting filter %s: %s", where, e)
where = simplify_to_supported_ops(where)
col.get(where=where) Prevention
- Keep a single shared filter-builder helper that only emits supported operators.
- Add unit tests asserting every filter your app produces passes the supported-operator check.
- When porting from Chroma/Mongo syntax, grep filters for $nor/$not/$regex/$nin before switching backends.
When it happens
Trigger: Calling count/get/query/delete on a SQLiteExactCollection with a `where` dict containing an operator outside the supported set, e.g. `{"$nor": [...]}`, `{"$not": {...}}`, or a typo like `"$GTE"`. Nested operator dicts and operator dicts inside lists are also traversed, so the bad key can sit at any depth.
Common situations: Porting filter code from ChromaDB/MongoDB syntax to the sqlite_exact backend; using `$in`/`$nin` list forms the backend never implemented; copy-pasting filters from another storage layer during a backend migration.
Related errors
- Milvus filter field {name!r} is not a safe identifier
- $in requires a non-empty list for {field!r}
- $nin requires a non-empty list for {field!r}
- operator {op!r} not supported by sqlite_exact
- where_document operator {key!r} not supported
AI-assisted analysis of MemPalace/mempalace@06cb6987f0 (2026-08-15).
Data as JSON: /api/errors/0548384f9ea2dc7e.
Report an issue: GitHub.