{"record":{"id":"1ddc0921d4c1c158","repo":"HumanSignal/label-studio","slug":"column-name-cannot-contain-unqueryable-column-nam","errorCode":null,"errorMessage":"Column name cannot contain {UNQUERYABLE_COLUMN_NAME_CHARACTERS}.","messagePattern":"Column name cannot contain (.+?)\\.","errorType":"validation","errorClass":"ValidationError","httpStatus":400,"severity":"error","filePath":"label_studio/data_manager/actions/data_columns.py","lineNumber":48,"sourceCode":"    )\n    value_type = request_data.get('value_type', 'String')\n    value = request_data.get('value', '')\n\n    if value_type not in {'String', 'Number', 'Expression'}:\n        raise ValidationError({'value_type': 'Choose a supported column type.'})\n\n    if not isinstance(value_name, str) or not value_name.strip():\n        raise ValidationError({'column_name': 'Select an existing column or enter a new column name.'})\n\n    value_name = value_name.strip()\n    column_exists = value_name in project.summary.all_data_columns\n    if not column_exists:\n        column_exists = project.tasks.filter(data__has_key=value_name).exists()\n    mode = 'update' if column_exists else 'add'\n    # Existing columns (e.g. imported spreadsheet headers) stay editable, but a new column must be\n    # one the Data Manager can filter and sort on.\n    if mode == 'add' and not is_queryable_column_name(value_name):\n        raise ValidationError(\n            {'column_name': f'Column name cannot contain {UNQUERYABLE_COLUMN_NAME_CHARACTERS}.'},\n        )\n    try:\n        value = {'String': str, 'Number': float, 'Expression': str}[value_type](value)\n    except (TypeError, ValueError) as exc:\n        raise ValidationError({'value': f'Enter a valid {value_type.lower()} value.'}) from exc\n\n    return mode, value_name, value_type, value\n\n\ndef _set_data_value_in_batches(queryset, value_name, postgres_value, sqlite_value):\n    if settings.DJANGO_DB == settings.DJANGO_DB_SQLITE:\n        updated_count = 0\n        task_iterator = iterate_queryset(queryset.only('id', 'data'), chunk_size=settings.UPDATE_COLUMN_BATCH_SIZE)\n        for task_batch in batched_iterator(task_iterator, settings.UPDATE_COLUMN_BATCH_SIZE):\n            for task in task_batch:\n                task.data = task.data or {}\n                task.data[value_name] = sqlite_value(task)","sourceCodeStart":30,"sourceCodeEnd":66,"githubUrl":"https://github.com/HumanSignal/label-studio/blob/0b49e9b53917880baf1dd85d574fe5541a9aafb2/label_studio/data_manager/actions/data_columns.py#L30-L66","documentation":"For a NEW column (mode 'add'), the name must pass is_queryable_column_name — it must be filterable/sortable by the Data Manager. Names containing characters in UNQUERYABLE_COLUMN_NAME_CHARACTERS (e.g. dots/dollar signs used by nested JSON paths) are rejected with ValidationError {'column_name': 'Column name cannot contain ...'}. Existing columns (e.g. imported spreadsheet headers) are exempt and stay editable.","triggerScenarios":"Adding a column whose name contains characters like '.' or '$', e.g. column_name 'user.email' when that column does not already exist in project data.","commonSituations":"Trying to create nested-path style columns ('a.b') mimicking existing dotted keys; spreadsheet headers with dots when re-importing; automation generating column names with dots/dollars.","solutions":["Rename the new column to exclude unqueryable characters (use '_' instead of '.').","If the column already exists in task data, it is treated as 'update' mode and allowed — verify the exact name matches the existing key.","Sanitize generated column names before calling the action."],"exampleFix":"// before\ncolumn_name = 'user.email'\n// after\ncolumn_name = 'user_email'","handlingStrategy":"validation","validationCode":"import re\nFORBIDDEN = set('.$[]{}\"\\\\ *?<>|,:;/')  # mirror UNQUERYABLE_COLUMN_NAME_CHARACTERS\ndef assert_queryable_new_column(name, existing_columns):\n    if name in existing_columns:\n        return\n    bad = [c for c in name if c in FORBIDDEN]\n    assert not bad, f'column name contains unqueryable characters: {bad}'","typeGuard":"def is_safe_column_name(name):\n    return isinstance(name, str) and bool(name.strip()) and not any(ch in name for ch in '.$[]\"\\\\')","tryCatchPattern":"from rest_framework.exceptions import ValidationError\ntry:\n    add_data_field(project, qs, request=request)\nexcept ValidationError as e:\n    if 'column_name' in e.message_dict and 'cannot contain' in str(e):\n        sanitize_and_retry()","preventionTips":["Replace dots/dollar signs with underscores in generated column names.","Check whether the column already exists (existing names are exempt).","Unit-test column-name generation against forbidden characters."],"tags":["django","validation","data-manager","columns","naming"],"backgroundTag":"invalid-field-name","analyzedSha":"0b49e9b53917880baf1dd85d574fe5541a9aafb2","analyzedAt":"2026-08-29T00:39:52.578Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}