{"record":{"id":"89d8fb4474e28ee6","repo":"makeplane/plane","slug":"operator-in-leaf","errorCode":"operator_in_leaf","errorMessage":"Logical operators cannot appear in a leaf filter object","messagePattern":"Logical operators cannot appear in a leaf filter object","errorType":"validation","errorClass":"DRFValidationError","httpStatus":400,"severity":"error","filePath":"apps/api/plane/utils/filters/filter_backend.py","lineNumber":423,"sourceCode":"                self._validate_structure(value, max_depth=max_depth, current_depth=current_depth + 1)\n                return\n\n        # Leaf node: validate fields and values\n        self._validate_leaf(node)\n\n    def _validate_leaf(self, leaf):\n        \"\"\"Validate a leaf dict containing field lookups and values.\"\"\"\n        if not isinstance(leaf, dict) or not leaf:\n            raise DRFValidationError(\n                {\n                    \"message\": \"Leaf filter must be a non-empty JSON object\",\n                    \"code\": \"invalid_leaf\",\n                }\n            )\n\n        for key, value in leaf.items():\n            if isinstance(key, str) and key.lower() in (\"or\", \"and\", \"not\"):\n                raise DRFValidationError(\n                    {\n                        \"message\": \"Logical operators cannot appear in a leaf filter object\",\n                        \"code\": \"operator_in_leaf\",\n                    }\n                )\n\n            # Lists/Tuples must contain only scalar values\n            if isinstance(value, (list, tuple)):\n                if len(value) == 0:\n                    raise DRFValidationError(\n                        {\n                            \"message\": f\"List value for '{key}' must not be empty\",\n                            \"code\": \"empty_list_value\",\n                        }\n                    )\n                for item in value:\n                    if not self._is_scalar(item):\n                        raise DRFValidationError(","sourceCodeStart":405,"sourceCodeEnd":441,"githubUrl":"https://github.com/makeplane/plane/blob/1c8a60f858d8472aa56e29994ec1c7926da2c6ce/apps/api/plane/utils/filters/filter_backend.py#L405-L441","documentation":"Raised by _validate_leaf when a leaf object contains a key whose lowercase form is 'or', 'and', or 'not'. After structural dispatch, a leaf should contain only field keys; the presence of a reserved operator word inside a leaf means the schema was mis-assembled (the operator should have been at a parent level).","triggerScenarios":"GET .../?filters={\"state\":\"open\",\"and\":\"something\"} (and treated as a field name inside a leaf); GET .../?filters={\"OR\":{...}} where OR is mis-cased inside a leaf context; clients that allow operator keywords as field names.","commonSituations":"Custom-property or column named 'and'/'or'/'not' that the client forwards as a field key; merging an operator fragment into a leaf dict; case variations (Or, AND) the client assumed would be treated as fields.","solutions":["Move the operator to its own parent level so the leaf contains only field keys.","If a real field is named 'and'/'or'/'not', rename it or wrap it under a different key; the grammar reserves these words case-insensitively.","Validate client-side that no field name lower-cases to an operator keyword."],"exampleFix":"// before\n?filters={\"state\":\"open\",\"and\":\"priority\"}\n// after\n?filters={\"and\":[{\"state\":\"open\"},{\"priority\":\"high\"}]}","handlingStrategy":"validation","validationCode":"RESERVED = {'or', 'and', 'not'}\ndef assert_no_reserved_in_leaf(leaf):\n    for k in leaf:\n        if isinstance(k, str) and k.lower() in RESERVED:\n            raise ValueError(f\"'{k}' is reserved and cannot be a field name in a leaf\")","typeGuard":"const RESERVED = new Set(['or','and','not']);\nfunction leafHasNoReservedKeys(leaf) {\n  return Object.keys(leaf).every(k => !RESERVED.has(k.toLowerCase()));\n}","tryCatchPattern":null,"preventionTips":["Rename real fields that collide with or/and/not; matching is case-insensitive.","Place operator keywords at the parent level, never alongside field keys."],"tags":["filters","schema","reserved-key","api"],"backgroundTag":null,"analyzedSha":"1c8a60f858d8472aa56e29994ec1c7926da2c6ce","analyzedAt":"2026-08-12T14:44:31.636Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}