makeplane/plane · error · DRFValidationError
invalid_value_type
invalid_value_type
Error message
Value for '{key}' must be a scalar, null, or list/tuple of scalars What it means
Raised by _validate_leaf when a leaf field's value is not a scalar, not None, and not a list/tuple. The backend only allows None, str/int/float/bool, or lists of scalars; passing a bare dict, a set, or any other object as a field value is rejected because it cannot be coerced into the QueryDict string form the filterset expects.
Source
Thrown at apps/api/plane/utils/filters/filter_backend.py:451
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
- Replace dict/object values with the relevant scalar: {"state":"open"} or {"state_id":3}.
- If you need sub-field matching, declare it as a relationship filter on the filterset and use the appropriate lookup suffix.
- Convert Python sets to lists before serializing.
Example fix
// before
?filters={"state":{"name":"open"}}
// after
?filters={"state":"open"} Defensive patterns
Strategy: type-guard
Validate before calling
def assert_leaf_values_scalar(leaf):
for k, v in leaf.items():
if isinstance(v, (list, tuple)):
continue
if not (v is None or isinstance(v, (str, int, float, bool))):
raise ValueError(f"value for '{k}' must be scalar or null, got {type(v).__name__}") Type guard
function isScalarOrNull(v) {
return v === null || typeof v === 'string' || typeof v === 'number' || typeof v === 'boolean';
}
function leafValuesAreScalar(leaf) {
return Object.entries(leaf).every(([k, v]) => Array.isArray(v) || isScalarOrNull(v));
} Prevention
- Send scalar IDs/names, not object representations, as field values.
- Convert Python sets to lists before serializing.
When it happens
Trigger: GET .../?filters={"state":{"name":"open"}} (dict as value); GET .../?filters={"priority":{}} ; programmatic input that forwards a Django model instance or set object as a value.
Common situations: Client reuses an object representation where a scalar ID/name is expected; Python callers passing a set instead of a list; nested filter fragment mistaken for a value.
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/c3430b7544f64452.
Report an issue: GitHub.