makeplane/plane · error · DRFValidationError

invalid_operator_child_type

invalid_operator_child_type

Error message

All children of '{op}' must be JSON objects

What it means

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.

Source

Thrown at apps/api/plane/utils/filters/filter_backend.py:384

                        "message": (f"Cannot mix logical operator '{op_key}' with field keys at the same level"),
                        "code": "mixed_operator_and_fields",
                    }
                )

            op = op_key.lower()
            value = node[op_key]

            if op in ("or", "and"):
                if not isinstance(value, list) or len(value) == 0:
                    raise DRFValidationError(
                        {
                            "message": f"'{op}' must be a non-empty list of filter objects",
                            "code": "invalid_operator_children",
                        }
                    )
                for child in value:
                    if not isinstance(child, dict):
                        raise DRFValidationError(
                            {
                                "message": f"All children of '{op}' must be JSON objects",
                                "code": "invalid_operator_child_type",
                            }
                        )
                    self._validate_structure(
                        child,
                        max_depth=max_depth,
                        current_depth=current_depth + 1,
                    )
                return

            if op == "not":
                if not isinstance(value, dict):
                    raise DRFValidationError(
                        {
                            "message": "'not' must be a single JSON object",
                            "code": "invalid_not_child",

View on GitHub (pinned to 1c8a60f858)

Solutions

  1. Wrap each child as an object: {"or":[{"state":"open"},{"priority":"high"}]}.
  2. When mapping field names to children, produce an object per field: fields.map(f => ({[f]: val})).
  3. Flatten any doubly-nested arrays before sending.

Example fix

// before
?filters={"or":["state","priority"]}
// after
?filters={"or":[{"state":"open"},{"priority":"high"}]}
Defensive patterns

Strategy: type-guard

Validate before calling

def assert_or_and_children_are_dicts(node):
    for k, v in node.items():
        if isinstance(k, str) and k.lower() in ('or', 'and'):
            for i, c in enumerate(v):
                if not isinstance(c, dict):
                    raise ValueError(f"child #{i} of '{k}' is not an object")

Type guard

function childrenAreObjects(opValue) {
  return Array.isArray(opValue) && opValue.every(c => typeof c === 'object' && c !== null && !Array.isArray(c));
}

Prevention

When it happens

Trigger: GET .../?filters={"or":["state","priority"]} (strings as children); GET .../?filters={"and":[[{"state":"open"}]]} (nested array); GET .../?filters={"or":[5]}.

Common situations: 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.

Related errors


AI-assisted analysis of makeplane/plane@1c8a60f858 (2026-08-12). Data as JSON: /api/errors/8733c91a913b06bf. Report an issue: GitHub.