HumanSignal/label-studio · error · ValueError
Child filters cannot contain nested child filters
Error message
Child filters cannot contain nested child filters
What it means
Pydantic model validator validate_one_nesting_level on the filter-group schema enforces that filters may be nested at most one level deep: if any filter's child_filters themselves contain child_filters, a ValueError('Child filters cannot contain nested child filters') is raised during request-body validation.
Source
Thrown at label_studio/data_manager/prepare_params.py:61
@child_filter.setter
def child_filter(self, value: Optional['Filter']) -> None:
self.child_filters = [] if value is None else [value]
class ConjunctionEnum(Enum):
OR = 'or'
AND = 'and'
class Filters(BaseModel):
conjunction: ConjunctionEnum
items: List[Filter]
@model_validator(mode='after')
def validate_one_nesting_level(self):
for item in self.items:
if any(child.child_filters for child in item.child_filters):
raise ValueError('Child filters cannot contain nested child filters')
return self
class SelectedItems(BaseModel):
all: bool
included: List[int] = []
excluded: List[int] = []
class PrepareParams(BaseModel):
project: Union[int, List[int]] # Support both single project and multiple projects
ordering: List[str] = []
selectedItems: Optional[SelectedItems] = None
filters: Optional[Filters] = None
data: Optional[dict] = None
request: Optional[Any] = None
@propertyView on GitHub (pinned to 0b49e9b539)
Solutions
- Flatten the filter tree to at most one nesting level before submitting — move grandchild conditions into a sibling filter group.
- Serialize conditions as multiple top-level filters combined by the group's conjunction.
- Guard the filter-building code so appended child_filters are always leaf filters.
- Wrap view submission in try/except ValueError (pydantic ValidationError) and show a nesting-depth message.
- Inspect the saved view payload (e.g. via API GET) and manually fix the nested structure in the DB/export.
Example fix
// before
{"items": [{"field": "f1", "child_filters": [{"field": "f2", "child_filters": [{"field": "f3", "child_filters": []}]}]}]}
// after
{"items": [{"field": "f1", "child_filters": [{"field": "f2", "child_filters": []}]}, {"field": "f3", "child_filters": []}]} Defensive patterns
Strategy: validation
Validate before calling
def enforce_single_nesting(filters):
for item in filters.get('items', []):
for child in item.get('child_filters', []):
if child.get('child_filters'):
child['child_filters'] = [] # flatten or reject
return filters Type guard
def is_one_level(filter_item: dict) -> bool:
return not any(c.get('child_filters') for c in filter_item.get('child_filters', [])) Try / catch
from pydantic import ValidationError
try:
params = PrepareParams.model_validate(request.data)
except ValidationError as e:
if 'nested child filters' in str(e):
payload['filters'] = enforce_single_nesting(payload['filters'])
params = PrepareParams.model_validate(payload)
else:
raise Prevention
- Design filter UIs as exactly two levels (group + leaves)
- Normalize/filter trees at the client boundary before sending
- Add a serializer-level test for deep-nested payloads
- When migrating old saved views, flatten them once at migration time
When it happens
Trigger: Submitting a data manager view (POST/PATCH) whose filters JSON has a filter_group containing a filter with child_filters, and at least one of those child filters also has non-empty child_filters (grandchildren).
Common situations: Frontend builds a recursive/nested filter UI and sends the whole tree; a view JSON was hand-edited or migrated from a version allowing deeper nesting; filters from saved views with old schemas are replayed.
Understand the failure class
Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.
Related errors
- `is any of` / `is none of` support Task ID, Inner ID, annota
- Filter value must be a list for `is any of` / `is none of`.
- Not supported filter type
- Can't find '{action_id}' in registered actions
- Choose a supported column type.
AI-assisted analysis of HumanSignal/label-studio@0b49e9b539 (2026-08-29).
Data as JSON: /api/errors/14e08f8bb9c750cc.
Report an issue: GitHub.