{"record":{"id":"986955ae2a4ec2fb","repo":"pathwaycom/pathway","slug":"pathway-schema-column-s-offending-collide-with-986955","errorCode":null,"errorMessage":"Pathway schema column(s) {offending} collide with the 'time' and 'diff' metadata columns appended by `pw.io.postgres.write_snapshot`. Rename the column(s) in your schema or migrate to `pw.io.postgres.write` with output_table_type='snapshot' (no metadata columns appended).","messagePattern":"Pathway schema column\\(s\\) (.+?) collide with the 'time' and 'diff' metadata columns appended by `pw\\.io\\.postgres\\.write_snapshot`\\. Rename the column\\(s\\) in your schema or migrate to `pw\\.io\\.postgres\\.write` with output_table_type='snapshot' \\(no metadata columns appended\\)\\.","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"python/pathway/io/postgres/__init__.py","lineNumber":1084,"sourceCode":"    # ``write_snapshot`` runs in ``legacy_mode=True`` which keeps the\n    # ``time``/``diff`` metadata columns on the writer's INSERT — and\n    # the generated SQL becomes ``INSERT INTO foo (\"time\", \"value\",\n    # \"time\", \"diff\") VALUES (...)`` if the user schema also carries a\n    # ``time`` or ``diff`` column, which PostgreSQL rejects with\n    # ``column \"time\" specified more than once``. The non-legacy\n    # sibling ``write`` runs the same check (and is already pinned by\n    # ``test_psql_write_stream_mode_rejects_reserved_column_name``);\n    # mirror it here so the deprecated path doesn't surface an opaque\n    # engine-worker ``db error``.\n    offending = sorted(\n        {\n            cname\n            for cname in table.schema.column_names()\n            if cname.lower() in (\"time\", \"diff\")\n        }\n    )\n    if offending:\n        raise ValueError(\n            f\"Pathway schema column(s) {offending} collide with \"\n            \"the 'time' and 'diff' metadata columns appended by \"\n            \"`pw.io.postgres.write_snapshot`. Rename the column(s) \"\n            \"in your schema or migrate to `pw.io.postgres.write` \"\n            \"with output_table_type='snapshot' (no metadata \"\n            \"columns appended).\"\n        )\n\n    postgres_settings = _augment_postgres_settings(postgres_settings, name)\n    data_storage = api.DataStorage(\n        storage_type=\"postgres\",\n        connection_string=_connection_string_from_settings(postgres_settings),\n        max_batch_size=max_batch_size,\n        snapshot_maintenance_on_output=True,\n        table_name=table_name,\n        schema_name=\"public\",\n        table_writer_init_mode=init_mode_from_str(init_mode),\n        legacy_mode=True,","sourceCodeStart":1066,"sourceCodeEnd":1102,"githubUrl":"https://github.com/pathwaycom/pathway/blob/fa2f74a4649b7c5908690cf60137263d8d80de5f/python/pathway/io/postgres/__init__.py#L1066-L1102","documentation":"Raised by the deprecated pw.io.postgres.write_snapshot when the Pathway schema contains a column named time or diff (case-insensitive). write_snapshot runs in legacy mode and appends its own time/diff metadata columns to every INSERT, so a user column with either name makes PostgreSQL reject the statement with 'column time specified more than once'. Pathway catches this before the run to avoid an opaque engine-worker db error.","triggerScenarios":"pw.io.postgres.write_snapshot with a schema declaring 'class time: ...' or 'class diff: ...' (any casing, e.g. Time, DIFF), or reading a source whose columns include time/diff and writing it straight to Postgres.","commonSituations":"Event/telemetry schemas that naturally carry a time column; changelog-derived tables with a diff column; CSV/JSON ingestion that keeps upstream column names verbatim.","solutions":["Rename the offending column in the schema (e.g. time -> event_time, diff -> delta) and re-run.","Rename upstream of the writer with table operations so the written schema no longer collides.","Best: migrate to pw.io.postgres.write with output_table_type='snapshot', which appends no metadata columns and accepts time/diff names."],"exampleFix":"# before\nclass EventSchema(pw.Schema):\n    time: float\n    value: int\npw.io.postgres.write_snapshot(t, conn, \"events\", primary_key=[\"time\"])\n\n# after\nclass EventSchema(pw.Schema):\n    event_time: float\n    value: int\npw.io.postgres.write(t, conn, \"events\", primary_key=[t.event_time], output_table_type=\"snapshot\")","handlingStrategy":"validation","validationCode":"reserved = {\"time\", \"diff\"}\ncolliding = {c for c in t.schema.column_names() if c.lower() in reserved}\nassert not colliding, f\"columns {colliding} collide with write_snapshot metadata\"\npw.io.postgres.write_snapshot(t, conn, \"t\", primary_key=[\"id\"])","typeGuard":"def snapshot_safe_schema(schema) -> bool:\n    return not ({c.lower() for c in schema.column_names()} & {\"time\", \"diff\"})","tryCatchPattern":null,"preventionTips":["Avoid naming columns time or diff in schemas destined for legacy Postgres writes.","Prefer pw.io.postgres.write(output_table_type='snapshot'), which appends no metadata columns.","Add a startup assert when writing with the deprecated API."],"tags":["pathway","postgres","deprecated","column-collision","snapshot"],"backgroundTag":null,"analyzedSha":"fa2f74a4649b7c5908690cf60137263d8d80de5f","analyzedAt":"2026-08-15T01:48:17.006Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}