makeplane/plane · error · DRFValidationError
non_scalar_list_item
non_scalar_list_item
Error message
List value for '{key}' must contain only scalar items What it means
Raised by _validate_leaf when a list/tuple value contains an item that is not a scalar. _is_scalar accepts None, str, int, float, bool; nested lists, dicts, or other objects inside a list value would not survive serialization into the QueryDict that feeds the filterset.
Source
Thrown at apps/api/plane/utils/filters/filter_backend.py:441
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:
raise DRFValidationError(
{
"message": f"List value for '{key}' must not be empty",
"code": "empty_list_value",
}
)
for item in value:
if not self._is_scalar(item):
raise DRFValidationError(
{
"message": f"List value for '{key}' must contain only scalar items",
"code": "non_scalar_list_item",
}
)
continue
# Scalars and None are allowed
if not self._is_scalar(value):
raise DRFValidationError(
{
"message": (f"Value for '{key}' must be a scalar, null, or list/tuple of scalars"),
"code": "invalid_value_type",
}
)
def _is_scalar(self, value):
return value is None or isinstance(value, (str, int, float, bool))View on GitHub (pinned to 1c8a60f858)
Solutions
- Flatten list values to scalars: {"state__in":["open","closed"]}.
- If the source is a list of objects, map to the scalar field first: objs.map(o => o.id).
- Validate each item with typeof checks before serializing.
Example fix
// before
?filters={"id__in":[{"id":1},{"id":2}]}
// after
?filters={"id__in":[1,2]} Defensive patterns
Strategy: type-guard
Validate before calling
def assert_list_items_scalar(leaf):
for k, v in leaf.items():
if isinstance(v, (list, tuple)):
for item in v:
if not (item is None or isinstance(item, (str, int, float, bool))):
raise ValueError(f"list value for '{k}' contains non-scalar item: {item!r}") Type guard
function isScalar(v) {
return v === null || typeof v === 'string' || typeof v === 'number' || typeof v === 'boolean';
}
function listValuesAreScalar(leaf) {
return Object.entries(leaf).every(([k, v]) => !Array.isArray(v) || v.every(isScalar));
} Prevention
- Map lists of objects to the scalar field before sending: objs.map(o => o.id).
- Flatten nested arrays in list values.
When it happens
Trigger: GET .../?filters={"state__in":[{"name":"open"}]} (list of objects); GET .../?filters={"tags__in":[['urgent']]} (nested array); GET .../?filters={"id__in":[123,"abc",[456]]}.
Common situations: Passing a list of ORM objects or dicts from a serializer; client that does not unwrap nested arrays; sending composite values where the filterset expects scalars.
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/e2b993ad711240bf.
Report an issue: GitHub.