{"record":{"id":"6360aa97fec8e6ff","repo":"pathwaycom/pathway","slug":"primary-key-field-names-must-be-specified-for-a-sn","errorCode":null,"errorMessage":"primary key field names must be specified for a snapshot mode","messagePattern":"primary key field names must be specified for a snapshot mode","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"python/pathway/io/postgres/__init__.py","lineNumber":897,"sourceCode":"            )\n        if primary_key is not None:\n            raise ValueError(\n                \"primary_key can only be specified for the snapshot table type\"\n            )\n    else:\n        # Snapshot mode requires at least one primary-key column —\n        # the writer's INSERT ... ON CONFLICT (...) DO UPDATE\n        # statement is malformed without one. If we let an empty list\n        # reach the engine it would error out only AFTER ``init_mode``\n        # has already mutated the destination (CREATE TABLE for\n        # ``\"replace\"`` / ``\"create_if_not_exists\"``), and under\n        # multi-worker (PATHWAY_THREADS > 1) the worker that loses the\n        # CREATE race observes the partially-created table and\n        # surfaces a less specific error instead — making any\n        # message-based test flaky. Reject at call time so no DB side\n        # effect happens.\n        if primary_key is None or len(primary_key) == 0:\n            raise ValueError(\n                \"primary key field names must be specified for a snapshot mode\"\n            )\n    if (\n        _external_diff_column is not None\n        and _external_diff_column._column.dtype != dtype.INT\n    ):\n        raise ValueError(\"_external_diff_column can only have an integer type\")\n\n    external_diff_column_index = get_column_index(table, _external_diff_column)\n    key_field_names = None\n    if primary_key is not None:\n        key_field_names = [pkey_field.name for pkey_field in primary_key]\n        # `primary_key=[other_table.col]` (or a reference whose name\n        # simply isn't in `table`) is accepted today but then either\n        # generates a malformed CREATE TABLE (``PRIMARY KEY\n        # (\"unknown\")``) on init or produces an UPSERT that panics at\n        # flush. Reject up-front with a clear message.\n        table_columns = set(table.schema.column_names())","sourceCodeStart":879,"sourceCodeEnd":915,"githubUrl":"https://github.com/pathwaycom/pathway/blob/fa2f74a4649b7c5908690cf60137263d8d80de5f/python/pathway/io/postgres/__init__.py#L879-L915","documentation":"Raised by pw.io.postgres.write() in snapshot mode when primary_key is None or an empty list. The snapshot writer maintains the destination with INSERT ... ON CONFLICT (...) DO UPDATE, which is malformed SQL without at least one key column; Pathway rejects it before any init_mode side effect (e.g. CREATE TABLE) touches the database.","triggerScenarios":"pw.io.postgres.write(table, parts, \"tbl\", output_table_type=\"snapshot\") with no primary_key, or primary_key=[].","commonSituations":"Users adding output_table_type=\"snapshot\" for upsert behavior but forgetting the key; tables whose schema has no primary_key column definition to rely on.","solutions":["Pass a non-empty key list: primary_key=[table.id].","If no natural key exists, add one to the schema (pw.column_definition(primary_key=True)) or synthesize one (e.g. pw.this.apply(...) hash) before writing.","If you cannot key the rows, use the default stream_of_changes mode instead."],"exampleFix":"# before\npw.io.postgres.write(t, parts, \"tbl\", output_table_type=\"snapshot\")\n# after\npw.io.postgres.write(t, parts, \"tbl\", output_table_type=\"snapshot\", primary_key=[t.doc_id])","handlingStrategy":"validation","validationCode":"if output_table_type == \"snapshot\":\n    assert primary_key, \"snapshot write needs at least one primary-key column\"","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Define primary_key=True on one schema column so a key always exists.","For keyless fact data, accept stream_of_changes semantics instead of forcing snapshot mode."],"tags":["postgres","pathway","snapshot","primary-key","validation"],"backgroundTag":null,"analyzedSha":"fa2f74a4649b7c5908690cf60137263d8d80de5f","analyzedAt":"2026-08-15T01:48:17.006Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}