{"record":{"id":"65f0ede49054b3bd","repo":"deepset-ai/haystack","slug":"operator-key-missing-in-condition","errorCode":null,"errorMessage":"'operator' key missing in {condition}","messagePattern":"'operator' key missing in (.+?)","errorType":"exception","errorClass":"FilterError","httpStatus":null,"severity":"error","filePath":"haystack/utils/filters.py","lineNumber":272,"sourceCode":"\nCOMPARISON_OPERATORS = {\n    \"==\": _equal,\n    \"!=\": _not_equal,\n    \">\": _greater_than,\n    \">=\": _greater_than_equal,\n    \"<\": _less_than,\n    \"<=\": _less_than_equal,\n    \"in\": _in,\n    \"not in\": _not_in,\n}\n\n\ndef _logic_condition(\n    condition: dict[str, Any], document: Document | ByteStream, strict_datetime_comparison: bool\n) -> bool:\n    if \"operator\" not in condition:\n        msg = f\"'operator' key missing in {condition}\"\n        raise FilterError(msg)\n    if \"conditions\" not in condition:\n        msg = f\"'conditions' key missing in {condition}\"\n        raise FilterError(msg)\n    operator: str = condition[\"operator\"]\n    if operator not in LOGICAL_OPERATORS:\n        msg = f\"Unknown logical operator '{operator}'. Valid operators are: {sorted(LOGICAL_OPERATORS)}\"\n        raise FilterError(msg)\n    conditions: list[dict[str, Any]] = condition[\"conditions\"]\n    return LOGICAL_OPERATORS[operator](\n        document=document, conditions=conditions, strict_datetime_comparison=strict_datetime_comparison\n    )\n\n\ndef _comparison_condition(\n    condition: dict[str, Any], document: Document | ByteStream, strict_datetime_comparison: bool\n) -> bool:\n    if \"field\" not in condition:\n        # 'field' key is only found in comparison dictionaries.","sourceCodeStart":254,"sourceCodeEnd":290,"githubUrl":"https://github.com/deepset-ai/haystack/blob/e318778c9bf60a1963e3b5f451359655dd696c30/haystack/utils/filters.py#L254-L290","documentation":"Logical filter conditions (AND/OR groups) must contain an 'operator' key. _logic_condition raises FilterError when the condition dict lacks it, indicating a malformed filter expression.","triggerScenarios":"Passing {\"conditions\": [...]} without the top-level 'operator' key to document_matches_filter or a store's filter application.","commonSituations":"Hand-written filter dicts in configs; merging/transforming filters programmatically and dropping keys; using the legacy single-dict filter syntax in a context expecting the new nested syntax.","solutions":["Add \"operator\": \"AND\" (or \"OR\") at the top of the logical condition.","Validate filter structure against the documented schema before use.","Check for code paths that strip or rename keys when building filters dynamically."],"exampleFix":"// before\nfilters = {\"conditions\": [{\"field\": \"meta.x\", \"operator\": \"==\", \"value\": 1}]}\n// after\nfilters = {\"operator\": \"AND\", \"conditions\": [{\"field\": \"meta.x\", \"operator\": \"==\", \"value\": 1}]}","handlingStrategy":"validation","validationCode":"assert \"operator\" in condition, f\"logical condition needs 'operator': {condition}\"","typeGuard":"def is_logical_condition(c: dict) -> bool:\n    return isinstance(c, dict) and \"operator\" in c and \"conditions\" in c","tryCatchPattern":"try:\n    ok = document_matches_filter(doc, filters)\nexcept FilterError as e:\n    raise ValueError(f\"malformed filter: {e}\") from e","preventionTips":["Include both 'operator' and 'conditions' in every logical group.","Validate filters against the documented schema before use.","Avoid manual dict surgery on filter structures."],"tags":["python","filters","schema-validation","haystack"],"backgroundTag":"missing-required-key","analyzedSha":"e318778c9bf60a1963e3b5f451359655dd696c30","analyzedAt":"2026-08-30T11:45:20.711Z","schemaVersion":2},"datasetVersion":"2026-08-30T13:17:10.514Z"}