makeplane/plane · error · DRFValidationError
invalid_leaf
invalid_leaf
Error message
Leaf filter must be a non-empty JSON object
What it means
Raised by _validate_leaf when the leaf node (an object with no or/and/not keys, reached at the end of _validate_structure) is not a dict or is an empty dict. Leaves must be non-empty JSON objects whose keys are field names; everything else is a structural error.
Source
Thrown at apps/api/plane/utils/filters/filter_backend.py:414
if op == "not":
if not isinstance(value, dict):
raise DRFValidationError(
{
"message": "'not' must be a single JSON object",
"code": "invalid_not_child",
}
)
self._validate_structure(value, max_depth=max_depth, current_depth=current_depth + 1)
return
# Leaf node: validate fields and values
self._validate_leaf(node)
def _validate_leaf(self, leaf):
"""Validate a leaf dict containing field lookups and values."""
if not isinstance(leaf, dict) or not leaf:
raise DRFValidationError(
{
"message": "Leaf filter must be a non-empty JSON object",
"code": "invalid_leaf",
}
)
for key, value in leaf.items():
if isinstance(key, str) and key.lower() in ("or", "and", "not"):
raise DRFValidationError(
{
"message": "Logical operators cannot appear in a leaf filter object",
"code": "operator_in_leaf",
}
)
# Lists/Tuples must contain only scalar values
if isinstance(value, (list, tuple)):
if len(value) == 0:View on GitHub (pinned to 1c8a60f858)
Solutions
- Route all nodes through _validate_structure rather than calling _validate_leaf directly.
- If you must call _validate_leaf, ensure the argument is a non-empty dict first.
- Keep the structural pre-checks intact when subclassing.
Example fix
# before
self._validate_leaf(None)
# after
if isinstance(node, dict) and node and not _is_operator_node(node):
self._validate_leaf(node) Defensive patterns
Strategy: validation
Validate before calling
def assert_leaf_ok(leaf):
if not isinstance(leaf, dict) or not leaf:
raise ValueError('leaf filter must be a non-empty object') Type guard
function isNonEmptyObject(v) {
return typeof v === 'object' && v !== null && !Array.isArray(v) && Object.keys(v).length > 0;
} Prevention
- Do not call _validate_leaf directly; let _validate_structure dispatch to it.
- Preserve the structural pre-checks when subclassing ComplexFilterBackend.
When it happens
Trigger: Structurally unreachable in the default pipeline because _validate_structure already rejects non-dict nodes (invalid_filter_node) and empty nodes (empty_filter_object) before dispatching to _validate_leaf. Can fire only in a subclass that calls _validate_leaf directly with bad input, or if _validate_structure is overridden to skip those checks.
Common situations: Subclassing ComplexFilterBackend and invoking _validate_leaf from custom code; unit tests that exercise _validate_leaf in isolation without preparing a proper dict.
Related errors
- invalid_filter_node
- empty_filter_object
- multiple_logical_operators
- mixed_operator_and_fields
- invalid_operator_children
AI-assisted analysis of makeplane/plane@1c8a60f858 (2026-08-12).
Data as JSON: /api/errors/5bc3f8218ae09893.
Report an issue: GitHub.