{"record":{"id":"323a2d1298b1b966","repo":"pathwaycom/pathway","slug":"pw-schema-has-column-names-that-differ-only-in-cas-323a2d","errorCode":null,"errorMessage":"pw.Schema has column names that differ only in case ({case_collisions}). SQL Server's default collation is case-insensitive, 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 \\((.+?)\\)\\. SQL Server's default collation is case-insensitive, so CREATE TABLE would reject them as duplicates\\. Rename these columns in the Pathway table so every column name is unique case-insensitively\\.","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"python/pathway/io/mssql/__init__.py","lineNumber":403,"sourceCode":"        raise ValueError(\n            \"primary_key can only be specified for the snapshot table type\"\n        )\n\n    value_fields = _format_output_value_fields(table)\n\n    # SQL Server's default collation matches identifiers case-insensitively\n    # (`id` and `ID` resolve to the same column), so any pair of schema\n    # columns that differ only in case would make CREATE TABLE fail with a\n    # raw \"duplicate column name\" driver error at pipeline-startup.  Surface\n    # the collision here with a Pathway-authored message instead.\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}). SQL Server's default collation is \"\n            \"case-insensitive, 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.  If the user's own schema already has a\n        # column with one of those names, the generated CREATE TABLE would\n        # declare it twice and SQL Server would reject it with an opaque\n        # \"duplicate column name\" error at startup.  Comparison is\n        # case-insensitive — SQL Server's default collation treats `Time` and\n        # `time` as the same identifier.\n        reserved_metadata_columns = {\"time\", \"diff\"}\n        collisions = sorted(\n            field.name","sourceCodeStart":385,"sourceCodeEnd":421,"githubUrl":"https://github.com/pathwaycom/pathway/blob/fa2f74a4649b7c5908690cf60137263d8d80de5f/python/pathway/io/mssql/__init__.py#L385-L421","documentation":"SQL Server's default collation compares identifiers case-insensitively, so `id` and `ID` are the same column name. If a Pathway table's schema contains column names that differ only in case, the CREATE TABLE emitted by pw.io.mssql.write would fail with a raw 'duplicate column name' driver error at pipeline startup. Pathway raises this ValueError at write() time with the colliding groups so the fix is obvious.","triggerScenarios":"Writing a table whose schema declares two columns whose lowercased names match, e.g. class S(pw.Schema): userId: int and UserID: str, then calling pw.io.mssql.write(table, ...) in either output mode.","commonSituations":"Renaming columns with .rename() or .select() and accidentally producing case variants; joining/unioning tables from sources with different casing conventions (userId vs UserId); schemas written by different team members with inconsistent casing.","solutions":["Rename the colliding columns in the Pathway table before writing, e.g. with table.select(**{\"user_id\": table.userId, \"user_id_upper\": table.UserID}) or table.rename().","Standardize casing conventions across the pipeline (PEP 8 snake_case) so collisions cannot arise.","Drop one of the duplicated-case columns before the sink if it is redundant."],"exampleFix":"# before\nresult = table.select(table.userId, table.UserID)\npw.io.mssql.write(result, \"t\", output_table_type=\"snapshot\")\n\n# after\nresult = table.select(user_id=table.userId, user_id_src=table.UserID)\npw.io.mssql.write(result, \"t\", output_table_type=\"snapshot\")","handlingStrategy":"validation","validationCode":"def case_collisions(column_names: list[str]) -> list[list[str]]:\n    groups: dict[str, list[str]] = {}\n    for n in column_names:\n        groups.setdefault(n.lower(), []).append(n)\n    return [sorted(g) for g in groups.values() if len(g) > 1]\n\nassert not case_collisions(table.schema.column_names()), \"case-insensitive collisions present\"","typeGuard":"def is_case_unique(column_names: list[str]) -> bool:\n    lowered = [n.lower() for n in column_names]\n    return len(lowered) == len(set(lowered))","tryCatchPattern":"try:\n    pw.io.mssql.write(table, \"t\", output_table_type=\"snapshot\")\nexcept ValueError as e:\n    if \"differ only in case\" in str(e):\n        raise SystemExit(\"Rename case-colliding columns before the MSSQL sink\") from e\n    raise","preventionTips":["Standardize on snake_case column names across the pipeline.","After joins/renames/selects on sink-bound tables, assert case-uniqueness of column names.","Remember SQL Server's default collation is case-insensitive when targeting it."],"tags":["mssql","sql-server","case-insensitive","schema","sink","pathway"],"backgroundTag":null,"analyzedSha":"fa2f74a4649b7c5908690cf60137263d8d80de5f","analyzedAt":"2026-08-15T01:48:17.006Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}