{"record":{"id":"be1900cf494202bc","repo":"pathwaycom/pathway","slug":"pw-schema-has-column-names-that-differ-only-in-cas-be1900","errorCode":null,"errorMessage":"pw.Schema has column names that differ only in case ({case_collisions}). SQLite treats identifiers case-insensitively, so CREATE TABLE would reject them as duplicates. Rename these columns in the Pathway table so every column name is unique case-insensitively.","messagePattern":"pw\\.Schema has column names that differ only in case \\((.+?)\\)\\. SQLite treats identifiers case-insensitively, so CREATE TABLE would reject them as duplicates\\. Rename these columns in the Pathway table so every column name is unique case-insensitively\\.","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"python/pathway/io/sqlite/__init__.py","lineNumber":324,"sourceCode":"    _reject_directory_path(path_str)\n\n    value_fields = _format_output_value_fields(table)\n\n    # SQLite identifier matching is case-insensitive (`ID` and `id` are\n    # the same column), so any pair of schema columns whose names\n    # differ only in case would make ``CREATE TABLE`` fail with a raw\n    # ``duplicate column name`` driver error at pipeline-start. Surface\n    # the collision here with a clear, Pathway-authored message\n    # instead, matching how the ``time`` / ``diff`` reserved-name check\n    # below works.\n    case_groups: dict[str, list[str]] = {}\n    for field in value_fields:\n        case_groups.setdefault(field.name.lower(), []).append(field.name)\n    case_collisions = [\n        sorted(names) for names in case_groups.values() if len(names) > 1\n    ]\n    if case_collisions:\n        raise ValueError(\n            f\"pw.Schema has column names that differ only in case \"\n            f\"({case_collisions}). SQLite treats identifiers \"\n            \"case-insensitively, so CREATE TABLE would reject them as \"\n            \"duplicates. Rename these columns in the Pathway table so \"\n            \"every column name is unique case-insensitively.\"\n        )\n\n    if not is_snapshot_mode:\n        # Stream-of-changes mode appends `time` / `diff` metadata columns\n        # to the destination table so the output can be replayed as a\n        # change log. If the user's own schema already has a column with\n        # one of those names, the generated CREATE TABLE would declare\n        # that column twice and SQLite would reject it. Catch this at\n        # write() time with a clear message instead of letting the user\n        # hit an opaque \"duplicate column name\" error at start-up.\n        # Matching is case-insensitive, consistent with SQLite's identifier\n        # comparison rules.\n        reserved_metadata_columns = {\"time\", \"diff\"}","sourceCodeStart":306,"sourceCodeEnd":342,"githubUrl":"https://github.com/pathwaycom/pathway/blob/fa2f74a4649b7c5908690cf60137263d8d80de5f/python/pathway/io/sqlite/__init__.py#L306-L342","documentation":"SQLite compares identifiers case-insensitively (ASCII), so columns named e.g. `ID` and `id` in a Pathway schema would collapse into one destination column and make the generated CREATE TABLE fail with a raw 'duplicate column name' driver error. Pathway's sqlite write() pre-validates the schema at call time and raises this clearer ValueError listing the colliding case-groups, e.g. [['ID', 'id']].","triggerScenarios":"Calling pw.io.sqlite.write() on a table whose schema contains two or more columns whose names differ only in case (owner/OWNER, pet/Pet), with any init_mode that creates the table (or even before that, since the check is unconditional).","commonSituations":"Schema defined from external sources (CSV headers, JSON keys, REST payloads) where casing varies between fields; renaming one column by capitalizing it while the original still exists; cross-team schemas combining snake_case and CamelCase variants of the same field.","solutions":["Rename the colliding columns in the Pathway table before writing, e.g. with table.select(**{...}) or table.rename_columns(), so every name is unique case-insensitively.","Drop one of the duplicate-cased columns with table.without() if it is a redundant duplicate.","Fix the upstream schema definition (pw.Schema class or input connector format) that produced the near-duplicate names."],"exampleFix":"# before\nt = pw.debug.table_from_markdown('''\nID | Id\n1  | 2\n''')\npw.io.sqlite.write(t, \"db.sqlite\", \"t\", init_mode=\"replace\")\n\n# after\nt = t.select(pw.this.ID, id2=pw.this.Id)\npw.io.sqlite.write(t, \"db.sqlite\", \"t\", init_mode=\"replace\")","handlingStrategy":"validation","validationCode":"def check_case_unique_columns(table):\n    groups = {}\n    for name in table.schema.column_names():\n        groups.setdefault(name.lower(), []).append(name)\n    collisions = [v for v in groups.values() if len(v) > 1]\n    if collisions:\n        raise ValueError(f\"case-insensitive column collisions: {collisions}\")\n    return True","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Standardize on one casing convention (e.g. snake_case) for all schema columns at ingest time.","When loading schemas from external files/APIs, normalize or assert case-unique column names before building the pipeline."],"tags":["pathway","sqlite","schema","case-sensitivity"],"backgroundTag":null,"analyzedSha":"fa2f74a4649b7c5908690cf60137263d8d80de5f","analyzedAt":"2026-08-15T01:48:17.006Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}