{"record":{"id":"8733c91a913b06bf","repo":"makeplane/plane","slug":"invalid-operator-child-type","errorCode":"invalid_operator_child_type","errorMessage":"All children of '{op}' must be JSON objects","messagePattern":"All children of '(.+?)' must be JSON objects","errorType":"validation","errorClass":"DRFValidationError","httpStatus":400,"severity":"error","filePath":"apps/api/plane/utils/filters/filter_backend.py","lineNumber":384,"sourceCode":"                        \"message\": (f\"Cannot mix logical operator '{op_key}' with field keys at the same level\"),\n                        \"code\": \"mixed_operator_and_fields\",\n                    }\n                )\n\n            op = op_key.lower()\n            value = node[op_key]\n\n            if op in (\"or\", \"and\"):\n                if not isinstance(value, list) or len(value) == 0:\n                    raise DRFValidationError(\n                        {\n                            \"message\": f\"'{op}' must be a non-empty list of filter objects\",\n                            \"code\": \"invalid_operator_children\",\n                        }\n                    )\n                for child in value:\n                    if not isinstance(child, dict):\n                        raise DRFValidationError(\n                            {\n                                \"message\": f\"All children of '{op}' must be JSON objects\",\n                                \"code\": \"invalid_operator_child_type\",\n                            }\n                        )\n                    self._validate_structure(\n                        child,\n                        max_depth=max_depth,\n                        current_depth=current_depth + 1,\n                    )\n                return\n\n            if op == \"not\":\n                if not isinstance(value, dict):\n                    raise DRFValidationError(\n                        {\n                            \"message\": \"'not' must be a single JSON object\",\n                            \"code\": \"invalid_not_child\",","sourceCodeStart":366,"sourceCodeEnd":402,"githubUrl":"https://github.com/makeplane/plane/blob/1c8a60f858d8472aa56e29994ec1c7926da2c6ce/apps/api/plane/utils/filters/filter_backend.py#L366-L402","documentation":"Raised by _validate_structure when an element inside an or/and list is not a dict. The list must contain only JSON objects (each of which is itself a node subject to the same grammar); scalars or nested arrays are rejected.","triggerScenarios":"GET .../?filters={\"or\":[\"state\",\"priority\"]} (strings as children); GET .../?filters={\"and\":[[{\"state\":\"open\"}]]} (nested array); GET .../?filters={\"or\":[5]}.","commonSituations":"Client builds the children with .map(field => field) instead of .map(field => ({[field]: value})); a CSV-to-filter converter that lists field names directly; double-wrapping an array during serialization.","solutions":["Wrap each child as an object: {\"or\":[{\"state\":\"open\"},{\"priority\":\"high\"}]}.","When mapping field names to children, produce an object per field: fields.map(f => ({[f]: val})).","Flatten any doubly-nested arrays before sending."],"exampleFix":"// before\n?filters={\"or\":[\"state\",\"priority\"]}\n// after\n?filters={\"or\":[{\"state\":\"open\"},{\"priority\":\"high\"}]}","handlingStrategy":"type-guard","validationCode":"def assert_or_and_children_are_dicts(node):\n    for k, v in node.items():\n        if isinstance(k, str) and k.lower() in ('or', 'and'):\n            for i, c in enumerate(v):\n                if not isinstance(c, dict):\n                    raise ValueError(f\"child #{i} of '{k}' is not an object\")","typeGuard":"function childrenAreObjects(opValue) {\n  return Array.isArray(opValue) && opValue.every(c => typeof c === 'object' && c !== null && !Array.isArray(c));\n}","tryCatchPattern":null,"preventionTips":["When mapping field names to or/and children, produce { [field]: value } per field.","Do not push bare scalars or nested arrays into an operator list."],"tags":["filters","schema","validation","api"],"backgroundTag":null,"analyzedSha":"1c8a60f858d8472aa56e29994ec1c7926da2c6ce","analyzedAt":"2026-08-12T14:44:31.636Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}