{"record":{"id":"7f93168d9b2de25d","repo":"MemPalace/mempalace","slug":"or-requires-a-non-empty-list-of-clauses","errorCode":null,"errorMessage":"$or requires a non-empty list of clauses","messagePattern":"\\$or requires a non-empty list of clauses","errorType":"exception","errorClass":"UnsupportedFilterError","httpStatus":null,"severity":"error","filePath":"mempalace/backends/milvus.py","lineNumber":158,"sourceCode":"        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))\n    return \" and \".join(part for part in parts if part)\n\n\ndef translate_where(where: Optional[dict]) -> str:\n    \"\"\"Translate the portable metadata where DSL into a Milvus filter string.\"\"\"\n    if not where:\n        return \"\"\n    return _translate_clause(where)\n\n\ndef translate_where_document(where_document: Optional[dict]) -> str:\n    \"\"\"Translate the portable document filter subset into a Milvus filter.\"\"\"","sourceCodeStart":140,"sourceCodeEnd":176,"githubUrl":"https://github.com/MemPalace/mempalace/blob/06cb6987f02610784fefbad4b2bd5d026d164ba6/mempalace/backends/milvus.py#L140-L176","documentation":"Raised in _translate_clause() when a $or key's value is not a non-empty list. $or must be followed by a list of clause dicts that get parenthesized and joined with 'or'; a dict operand, scalar, or empty list is rejected with UnsupportedFilterError during translation. Identical contract to $and but for disjunction.","triggerScenarios":"where={\"$or\": {\"wing\": \"a\", \"wing\": \"b\"}} (dict, and also lossy), {\"$or\": []}, or {\"$or\": \"x\"}.","commonSituations":"Building 'any of these wings' filters from a name list; forgetting to wrap single alternatives in list+dict form.","solutions":["Use list form: {\"$or\": [{\"wing\": \"a\"}, {\"wing\": \"b\"}]}","For same-field alternatives prefer $in: {\"wing\": {\"$in\": [\"a\", \"b\"]}}","Skip the $or clause if the alternative list is empty"],"exampleFix":"// before\nwhere = {\"$or\": [{\"wing\": \"a\"}, {\"wing\": \"b\"}, ]} if names else {\"$or\": []}\n\n// after\nwhere = {\"wing\": {\"$in\": names}} if names else None","handlingStrategy":"validation","validationCode":"def build_or(clauses):\n    clauses = [c for c in clauses if c]\n    if not clauses:\n        return None\n    if len(clauses) == 1:\n        return clauses[0]\n    return {\"$or\": clauses}","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 \"$or\" in str(e):\n        raise ValueError(\"$or must be a non-empty list of clause dicts\") from e\n    raise","preventionTips":["Use $in for same-field alternatives instead of $or","Never emit $or: [] — skip the clause","Centralize disjunction building in one helper"],"tags":["milvus","filter","or-operator","dsl"],"backgroundTag":null,"analyzedSha":"06cb6987f02610784fefbad4b2bd5d026d164ba6","analyzedAt":"2026-08-15T03:03:36.213Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}