makeplane/plane · error · DRFValidationError

mixed_operator_and_fields

mixed_operator_and_fields

Error message

Cannot mix logical operator '{op_key}' with field keys at the same level

What it means

Raised by _validate_structure when a node has exactly one logical-operator key AND at least one other key. The grammar requires the operator object to contain *only* the operator — fields must live in a child object, never alongside or/and/not at the same level.

Source

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

                    "code": "empty_filter_object",
                }
            )

        logical_keys = [k for k in node.keys() if isinstance(k, str) and k.lower() in ("or", "and", "not")]

        if len(logical_keys) > 1:
            raise DRFValidationError(
                {
                    "message": ("A filter object cannot contain multiple logical operators at the same level"),
                    "code": "multiple_logical_operators",
                }
            )

        if len(logical_keys) == 1:
            op_key = logical_keys[0]
            # must not mix operator with other keys
            if len(node) != 1:
                raise DRFValidationError(
                    {
                        "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:

View on GitHub (pinned to 1c8a60f858)

Solutions

  1. Move sibling fields into a child of the operator: {"and":[{"or":[...]},{"priority":"high"}]}.
  2. When building objects programmatically, never dict.update an operator object with field keys.
  3. Treat operator objects as structural only — they hold either an or/and/not key or field keys, never both.

Example fix

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

Strategy: validation

Validate before calling

def assert_no_operator_field_mix(node):
    op_keys = [k for k in node if isinstance(k, str) and k.lower() in ('or','and','not')]
    if op_keys and len(node) > 1:
        raise ValueError(f'operator {op_keys[0]} cannot share a node with field keys')

Type guard

function operatorNodeIsPure(node) {
  const keys = Object.keys(node);
  const op = keys.find(k => ['or','and','not'].includes(k.toLowerCase()));
  return !op || keys.length === 1;
}

Prevention

When it happens

Trigger: GET .../?filters={"or":[{"state":"open"}],"priority":"high"} ; GET .../?filters={"state":"open","not":{"priority":"low"}}.

Common situations: Adding a quick field filter to an existing operator object via spread/merge; misunderstanding that fields cannot ride alongside the operator; legacy converter that flattens fields into the operator node.

Related errors


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