{"record":{"id":"8c10bb34f0bf0847","repo":"MemPalace/mempalace","slug":"in-requires-a-non-empty-list-for-field-r","errorCode":null,"errorMessage":"$in requires a non-empty list for {field!r}","messagePattern":"\\$in requires a non-empty list for (.+?)","errorType":"exception","errorClass":"UnsupportedFilterError","httpStatus":null,"severity":"error","filePath":"mempalace/backends/milvus.py","lineNumber":120,"sourceCode":"\ndef _field_name(name: str) -> str:\n    if not isinstance(name, str) or not _FIELD_RE.match(name):\n        raise UnsupportedFilterError(f\"Milvus filter field {name!r} is not a safe identifier\")\n    return name\n\n\ndef _translate_field(field: str, expected: Any) -> str:\n    field = _field_name(field)\n    if isinstance(expected, dict):\n        parts = []\n        for op, operand in expected.items():\n            if op == \"$eq\":\n                parts.append(f\"{field} == {_quote_value(operand)}\")\n            elif op == \"$ne\":\n                parts.append(f\"{field} != {_quote_value(operand)}\")\n            elif op == \"$in\":\n                if not isinstance(operand, list) or not operand:\n                    raise UnsupportedFilterError(f\"$in requires a non-empty list for {field!r}\")\n                items = \", \".join(_quote_value(item) for item in operand)\n                parts.append(f\"{field} in [{items}]\")\n            elif op == \"$nin\":\n                if not isinstance(operand, list) or not operand:\n                    raise UnsupportedFilterError(f\"$nin requires a non-empty list for {field!r}\")\n                items = \", \".join(_quote_value(item) for item in operand)\n                parts.append(f\"{field} not in [{items}]\")\n            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:","sourceCodeStart":102,"sourceCodeEnd":138,"githubUrl":"https://github.com/MemPalace/mempalace/blob/06cb6987f02610784fefbad4b2bd5d026d164ba6/mempalace/backends/milvus.py#L102-L138","documentation":"Raised in _translate_field() when the $in operator's operand is not a list or is an empty list. Milvus 'in [..]' over an empty set is invalid/meaningless, so the translator refuses it up front rather than sending a malformed filter. It is an UnsupportedFilterError thrown synchronously during where-clause translation, before any network call.","triggerScenarios":"where={\"wing\": {\"$in\": []}}, where={\"wing\": {\"$in\": \"people\"}} (string instead of list), or a filter built from an empty computed list, e.g. {\"tag\": {\"$in\": matching_tags}} where matching_tags ends up empty.","commonSituations":"Dynamically computed candidate sets (e.g. entity names found by a detector) that legitimately come back empty; the caller intends 'no matches' but the backend rejects the clause.","solutions":["Skip the query (return empty results) when the $in list would be empty — it can match nothing anyway","Guard before calling: if isinstance(v, dict) and '$in' in v and not v['$in']: return []","Ensure the operand is a real list: wrap single values as [value]"],"exampleFix":"// before\nwhere = {\"wing\": {\"$in\": found_wings}}  # found_wings == []\ncollection.query(query_texts=[q], where=where)\n\n// after\nif not found_wings:\n    return []\ncollection.query(query_texts=[q], where={\"wing\": {\"$in\": found_wings}})","handlingStrategy":"validation","validationCode":"def is_valid_in_filter(where: dict) -> bool:\n    for v in where.values():\n        if isinstance(v, dict) and \"$in\" in v:\n            operand = v[\"$in\"]\n            if not isinstance(operand, list) or not operand:\n                return False\n    return True","typeGuard":null,"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 \"$in\" in str(e):\n        return []  # empty candidate set matches nothing\n    raise","preventionTips":["Short-circuit queries with empty $in lists to empty results","In filter builders, coerce scalar operands to [value]","Test builder output against the supported-operator contract"],"tags":["milvus","filter","in-operator","validation"],"backgroundTag":null,"analyzedSha":"06cb6987f02610784fefbad4b2bd5d026d164ba6","analyzedAt":"2026-08-15T03:03:36.213Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}