deepset-ai/haystack · error

Invalid filter syntax. See https://docs.haystack.deepset.ai/

Error message

Invalid filter syntax. See https://docs.haystack.deepset.ai/docs/metadata-filtering for details.

What it means

InMemoryDocumentStore._validate_filters raises ValueError when a filters dict is provided but contains neither an 'operator' nor a 'conditions' key, meaning it does not follow Haystack's documented metadata filtering syntax.

Source

Thrown at haystack/document_stores/in_memory/document_store.py:535

            # Update statistics accordingly
            doc_stats = self._bm25_attr.pop(doc_id)
            freq = doc_stats.freq_token
            doc_len = doc_stats.doc_len

            self._freq_vocab_for_idf.subtract(Counter(freq.keys()))
            for token in freq:
                if self._freq_vocab_for_idf[token] <= 0:
                    del self._freq_vocab_for_idf[token]
            try:
                self._avg_doc_len = (self._avg_doc_len * (len(self._bm25_attr) + 1) - doc_len) / len(self._bm25_attr)
            except ZeroDivisionError:
                self._avg_doc_len = 0

    @staticmethod
    def _validate_filters(filters: dict[str, Any] | None) -> None:
        if filters and "operator" not in filters and "conditions" not in filters:
            raise ValueError(
                "Invalid filter syntax. See https://docs.haystack.deepset.ai/docs/metadata-filtering for details."
            )

    def delete_all_documents(self) -> None:
        """
        Deletes all documents in the document store.
        """
        if self._shared:
            _STORAGES[self.index] = {}
            _BM25_STATS_STORAGES[self.index] = {}
            _AVERAGE_DOC_LEN_STORAGES[self.index] = 0.0
            _FREQ_VOCAB_FOR_IDF_STORAGES[self.index] = Counter()
        else:
            self._local_storage = {}
            self._local_bm25_attr = {}
            self._local_avg_doc_len = 0.0
            self._local_freq_vocab_for_idf = Counter()

View on GitHub (pinned to e318778c9b)

Solutions

  1. Wrap the comparison in the documented syntax: {"operator": "AND", "conditions": [{"field": "...", "operator": "==", "value": ...}]}
  2. Use the shorthand single-comparison form {"field": ..., "operator": ..., "value": ...} which the engine also accepts via normalize (only if your version supports it)
  3. Consult https://docs.haystack.deepset.ai/docs/metadata-filtering and validate the dict shape before calling

Example fix

// before
store.filter_documents({"field": "meta.genre", "operator": "==", "value": "crime"})
// wrapped incorrectly without operator/conditions keys at top level
// after
store.filter_documents({"operator": "AND", "conditions": [{"field": "meta.genre", "operator": "==", "value": "crime"}]})
Defensive patterns

Strategy: validation

Validate before calling

def is_valid_haystack_filter(f):
    if f is None:
        return True
    return isinstance(f, dict) and ("operator" in f or "conditions" in f)

assert is_valid_haystack_filter(filters), "filters need top-level 'operator'/'conditions'"

Type guard

def is_filter_dict(f) -> bool:
    return isinstance(f, dict) and ("operator" in f or "conditions" in f)

Try / catch

try:
    docs = store.filter_documents(filters=filters)
except ValueError as e:
    if "Invalid filter syntax" in str(e):
        docs = store.filter_documents(filters={"operator": "AND", "conditions": [filters]})
    else:
        raise

Prevention

When it happens

Trigger: Calling filter_documents, embedding_retrieval, or similar with a malformed dict like {"field": "meta.x", "operator": "==", "value": 1} at the top level instead of wrapping it in {"operator": "AND", "conditions": [...]}.

Common situations: Porting code written for other frameworks' flat filter syntax, hand-built filter dicts missing the top-level operator, upgrading from older Haystack 1.x filter formats.

Related errors


AI-assisted analysis of deepset-ai/haystack@e318778c9b (2026-08-30). Data as JSON: /api/errors/fce011d45fe9549a. Report an issue: GitHub.