HumanSignal/label-studio · error · ValidationError

Cannot filter on column "{_filter.filter.removeprefix('filte

Error message

Cannot filter on column "{_filter.filter.removeprefix('filter:tasks:')}": column names cannot contain {UNQUERYABLE_COLUMN_NAME_CHARACTERS}.

What it means

apply_filters turns each filter's column name into a Django ORM path and query alias. Names containing whitespace, quotes, or control characters (UNQUERYABLE_COLUMN_NAME_CHARACTERS) make Django raise a bare ValueError, so the code proactively raises ValidationError telling the caller the column name is not queryable (UTC-1221 fix).

Source

Thrown at label_studio/data_manager/managers.py:901

                for value in _filter.value:
                    q &= ~Q(predictions__model_version__contains=value)
                filter_expressions.append(q)
                continue
            elif field_name == 'predictions_model_versions' and _filter.operator == Operator.EMPTY:
                value = cast_bool_from_str(_filter.value)
                filter_expressions.append(Q(predictions__model_version__isnull=value))
                continue

            # use other name because of model names conflict
            if field_name == 'file_upload':
                field_name = 'file_upload_field'

            # From here on the column name becomes an ORM path and query alias, which Django
            # rejects with a bare ValueError for names holding whitespace, quotes, control
            # characters and the like — for instance a task.data key imported from a spreadsheet
            # header. Report it as a client error instead of failing the request (UTC-1221).
            if not is_queryable_column_name(field_name):
                raise ValidationError(
                    f'Cannot filter on column "{_filter.filter.removeprefix("filter:tasks:")}": '
                    f'column names cannot contain {UNQUERYABLE_COLUMN_NAME_CHARACTERS}.'
                )

            # annotate with cast to number if need
            if _filter.type == 'Number' and field_name.startswith('data__'):
                json_field = field_name.replace('data__', '')
                queryset = queryset.annotate(
                    **{
                        f'filter_{json_field.replace("$undefined$", "undefined")}': Cast(
                            KeyTextTransform(json_field, 'data'), output_field=FloatField()
                        )
                    }
                )
                clean_field_name = f'filter_{json_field.replace("$undefined$", "undefined")}'
            else:
                clean_field_name = field_name

View on GitHub (pinned to 0b49e9b539)

Solutions

  1. Rename the task.data key to a queryable identifier (letters, digits, underscores) and re-import
  2. Sanitize data keys at import time (e.g. slugify headers: 'Customer Name' -> 'customer_name')
  3. Filter using the sanitized key: filter:tasks:data.customer_name
  4. Inspect UNQUERYABLE_COLUMN_NAME_CHARACTERS in managers.py to see exactly which characters are rejected

Example fix

// before
{"filter": "filter:tasks:data.Customer Name", "operator": "equal", "value": "Acme"}
// after
{"filter": "filter:tasks:data.customer_name", "operator": "equal", "value": "Acme"}
Defensive patterns

Strategy: validation

Validate before calling

import re
UNQUERYABLE = re.compile(r'[\s\'"\x00-\x1f]')
key = col_name
if UNQUERYABLE.search(key): key = re.sub(r'\W+', '_', key.strip())
filter_name = f'filter:tasks:data.{key}'

Type guard

const isQueryableKey = (k) => typeof k === 'string' && k.length > 0 && !/[\s'"\x00-\x1f]/.test(k);

Try / catch

try:
    apply_filters(...)
except ValidationError as e:
    if 'cannot contain' in str(e): slugify_data_keys_and_retry(e)
    else: raise

Prevention

When it happens

Trigger: Filtering on task.data.<key> where <key> comes from a spreadsheet header or imported JSON with spaces/quotes/newlines, e.g. data__Customer Name or data__"total".

Common situations: CSV/Excel imports creating column keys with spaces, slashes, or quotes; keys copied from column display labels instead of raw keys; control characters from copy-pasted headers.

Related errors


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