HumanSignal/label-studio · error · ValidationError

`is any of` / `is none of` support Task ID, Inner ID, annota

Error message

`is any of` / `is none of` support Task ID, Inner ID, annotation/prediction counters, and task.data.* fields.

What it means

validate_in_list_filter restricts the in_list / not_in_list operators to Task ID, Inner ID, annotation/prediction counters, and task.data.* fields (checked via _is_supported_in_list_field). Filtering any other column with these operators raises ValidationError. Legacy annotations_ids contains/not_contains filters are unaffected.

Source

Thrown at label_studio/data_manager/managers.py:582


def validate_in_list_filter(_filter, field_name: str) -> str:
    """Semantic validation for `in_list` / `not_in_list` operators (BROS-1203).

    Returns one of:
      - 'ok'   — proceed with the existing Q(__in=value) branch.
      - 'none' — empty `in_list` after normalization: append a contradiction so the
                 row contributes no matches (works correctly for both AND and OR).
      - 'skip' — empty `not_in_list` after normalization: drop the filter entirely.

    Raises ValidationError for unsupported fields. Only triggers when the *original*
    operator is in_list / not_in_list, so legacy ``annotations_ids`` contains/not_contains
    filters handled by ``annotation_id_filter_q`` remain unaffected.
    """
    if _filter.operator not in (Operator.IN_LIST, Operator.NOT_IN_LIST):
        return 'ok'
    if not _is_supported_in_list_field(field_name):
        raise ValidationError(
            '`is any of` / `is none of` support Task ID, Inner ID, annotation/prediction counters, '
            'and task.data.* fields.'
        )
    if not isinstance(_filter.value, list):
        raise ValidationError('Filter value must be a list for `is any of` / `is none of`.')
    _normalize_in_list_value(_filter)
    if not _filter.value:
        return 'none' if _filter.operator == Operator.IN_LIST else 'skip'
    return 'ok'


def add_result_filter(field_name, _filter, filter_expressions, project):
    from django.db.models.expressions import RawSQL
    from tasks.models import Annotation, Prediction

    _class = Annotation if field_name == 'annotations_results' else Prediction

    # Annotation

View on GitHub (pinned to 0b49e9b539)

Solutions

  1. Switch the operator to one supported by the target field (e.g. contains, equal)
  2. Restrict in_list/not_in_list usage to id, inner_id, annotation/prediction count fields, and data.<key> columns
  3. If list matching on another column is required, reshape the data so the value lives under task.data
  4. Update saved views that embed in_list on unsupported columns

Example fix

// before
{"filter": "filter:tasks:created_by", "operator": "in_list", "value": [1,2]}
// after
{"filter": "filter:tasks:data.my_field", "operator": "in_list", "value": [1,2]}
Defensive patterns

Strategy: validation

Validate before calling

from data_manager.managers import _is_supported_in_list_field
field = f['filter'].removeprefix('filter:tasks:')
if f['operator'] in ('in_list', 'not_in_list') and not _is_supported_in_list_field(field):
    raise ValueError(f"in_list not supported on {field}")

Type guard

def supports_in_list(field): from data_manager.managers import _is_supported_in_list_field; return _is_supported_in_list_field(field)

Try / catch

try:
    apply_filters(...)
except ValidationError as e:
    if 'is any of' in str(e) and 'support' in str(e): switch_operator_to_contains(e)
    else: raise

Prevention

When it happens

Trigger: A request filter with operator 'in_list' or 'not_in_list' on an unsupported field such as completed_at, created_by, or an arbitrary non-data column.

Common situations: Frontend UI exposing 'is any of' for every column; copied filter payloads from a task.data field applied to a metadata column; older exported views replayed against tightened validation.

Related errors


AI-assisted analysis of HumanSignal/label-studio@0b49e9b539 (2026-08-29). Data as JSON: /api/errors/d272acb6b66f84f5. Report an issue: GitHub.