{"record":{"id":"cb7a6d9d8e27e7f6","repo":"MemPalace/mempalace","slug":"where-clause-must-be-a-dict-got-type-clause-n","errorCode":null,"errorMessage":"where clause must be a dict, got {type(clause).__name__}","messagePattern":"where clause must be a dict, got (.+?)","errorType":"exception","errorClass":"UnsupportedFilterError","httpStatus":null,"severity":"error","filePath":"mempalace/backends/milvus.py","lineNumber":146,"sourceCode":"            elif op == \"$gt\":\n                parts.append(f\"{field} > {_quote_value(operand)}\")\n            elif op == \"$gte\":\n                parts.append(f\"{field} >= {_quote_value(operand)}\")\n            elif op == \"$lt\":\n                parts.append(f\"{field} < {_quote_value(operand)}\")\n            elif op == \"$lte\":\n                parts.append(f\"{field} <= {_quote_value(operand)}\")\n            elif op == \"$contains\":\n                parts.append(f\"{field} like {_like_value(operand)}\")\n            else:\n                raise UnsupportedFilterError(f\"operator {op!r} not supported by milvus\")\n        return \" and \".join(parts)\n    return f\"{field} == {_quote_value(expected)}\"\n\n\ndef _translate_clause(clause: dict) -> str:\n    if not isinstance(clause, dict):\n        raise UnsupportedFilterError(f\"where clause must be a dict, got {type(clause).__name__}\")\n    if not clause:\n        return \"\"\n    parts = []\n    for key, value in clause.items():\n        if key == \"$and\":\n            if not isinstance(value, list) or not value:\n                raise UnsupportedFilterError(\"$and requires a non-empty list of clauses\")\n            nested = [_translate_clause(item) for item in value]\n            parts.append(\"(\" + \" and \".join(part for part in nested if part) + \")\")\n        elif key == \"$or\":\n            if not isinstance(value, list) or not value:\n                raise UnsupportedFilterError(\"$or requires a non-empty list of clauses\")\n            nested = [_translate_clause(item) for item in value]\n            parts.append(\"(\" + \" or \".join(part for part in nested if part) + \")\")\n        elif key.startswith(\"$\"):\n            raise UnsupportedFilterError(f\"operator {key!r} not supported by milvus\")\n        else:\n            parts.append(_translate_field(key, value))","sourceCodeStart":128,"sourceCodeEnd":164,"githubUrl":"https://github.com/MemPalace/mempalace/blob/06cb6987f02610784fefbad4b2bd5d026d164ba6/mempalace/backends/milvus.py#L128-L164","documentation":"Raised by _translate_clause() when the where argument (or a nested $and/$or element) is not a dict — e.g. a list, string, or None inside a nested position. The portable DSL requires every clause level to be a mapping of field→condition or operator→subclauses; anything else fails translation with UnsupportedFilterError before Milvus is contacted. Note the top-level falsy case ({}, None) is fine and yields an empty filter — only non-dict truthy values fail.","triggerScenarios":"where=[{\"wing\": \"a\"}] (list-wrapped clause, Mongo habit), where=\"wing = 'a'\" (raw expression string), or nested={\"$or\": [{\"a\": 1}, \"b\"]} where one $or element is a bare string.","commonSituations":"Copy-pasting raw Milvus filter expression strings from Milvus docs into the where parameter; JSON-decoded filters where a nested element is not an object; wrappers that accept multiple clause shapes.","solutions":["Pass a plain dict: where={\"wing\": \"alice\"}, not a list or expression string","For raw Milvus filter expressions, use the backend's native filter escape hatch (if exposed) instead of where","Validate nested $and/$or elements are all dicts before calling query"],"exampleFix":"// before\nresults = collection.query(query_texts=[q], where=[{\"wing\": \"alice\"}])\n\n// after\nresults = collection.query(query_texts=[q], where={\"wing\": \"alice\"})","handlingStrategy":"type-guard","validationCode":"def validate_where(where) -> dict:\n    if not where:\n        return {}\n    if not isinstance(where, dict):\n        raise TypeError(f\"where must be a dict, got {type(where).__name__}\")\n    for k, v in where.items():\n        if k in (\"$and\", \"$or\"):\n            for item in v:\n                validate_where(item)\n    return where","typeGuard":"def is_where_dict(where) -> bool:\n    \"\"\"True when every clause node is a dict and $and/$or carry list-of-dict.\"\"\"\n    if not isinstance(where, dict):\n        return False\n    for k, v in where.items():\n        if k in (\"$and\", \"$or\"):\n            if not isinstance(v, list) or not v:\n                return False\n            if not all(is_where_dict(item) for item in v):\n                return False\n    return True","tryCatchPattern":"from mempalace.backends.base import UnsupportedFilterError\ntry:\n    collection.query(query_texts=[q], where=where, n_results=k)\nexcept UnsupportedFilterError as e:\n    if \"must be a dict\" in str(e):\n        raise TypeError(\"pass where as a dict, not a list or expression string\") from e\n    raise","preventionTips":["Always author where as a plain dict","Do not feed raw Milvus expression strings into where","Validate deserialized JSON filters before querying"],"tags":["milvus","filter","type-validation","where-clause"],"backgroundTag":null,"analyzedSha":"06cb6987f02610784fefbad4b2bd5d026d164ba6","analyzedAt":"2026-08-15T03:03:36.213Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}