{"record":{"id":"a9d451ff38bee3eb","repo":"pathwaycom/pathway","slug":"pw-io-mysql-read-primary-key-column-s-nullable-p","errorCode":null,"errorMessage":"pw.io.mysql.read primary_key column(s) {nullable_pks} are declared nullable; primary-key columns must be non-nullable so the connector can derive a unique row identity. NULL values would collide on the same Pathway key and change tracking would silently merge unrelated rows.","messagePattern":"pw\\.io\\.mysql\\.read primary_key column\\(s\\) (.+?) are declared nullable; primary-key columns must be non-nullable so the connector can derive a unique row identity\\. NULL values would collide on the same Pathway key and change tracking would silently merge unrelated rows\\.","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"python/pathway/io/mysql/__init__.py","lineNumber":202,"sourceCode":"    \"\"\"\n    _check_entitlements(\"mysql\")\n\n    schema, api_schema = read_schema(schema)\n\n    primary_key_columns = schema.primary_key_columns()\n    if not primary_key_columns:\n        raise ValueError(\n            \"pw.io.mysql.read requires at least one primary key column in the schema. \"\n            \"Mark the column(s) that form the table's primary key with \"\n            \"pw.column_definition(primary_key=True).\"\n        )\n\n    pk_dtypes = schema._dtypes()\n    nullable_pks = [\n        name for name in primary_key_columns if isinstance(pk_dtypes[name], dt.Optional)\n    ]\n    if nullable_pks:\n        raise ValueError(\n            f\"pw.io.mysql.read primary_key column(s) {nullable_pks} are declared \"\n            \"nullable; primary-key columns must be non-nullable so the connector \"\n            \"can derive a unique row identity. NULL values would collide on the \"\n            \"same Pathway key and change tracking would silently merge unrelated \"\n            \"rows.\"\n        )\n\n    is_streaming = mode == \"streaming\"\n\n    data_storage = api.DataStorage(\n        storage_type=\"mysql\",\n        connection_string=connection_string,\n        table_name=table_name,\n        mode=(\n            api.ConnectorMode.STREAMING if is_streaming else api.ConnectorMode.STATIC\n        ),\n        mysql_server_id=server_id,\n    )","sourceCodeStart":184,"sourceCodeEnd":220,"githubUrl":"https://github.com/pathwaycom/pathway/blob/fa2f74a4649b7c5908690cf60137263d8d80de5f/python/pathway/io/mysql/__init__.py#L184-L220","documentation":"The MySQL connector derives each row's Pathway key from the schema's primary-key columns; NULL key parts would make distinct rows collide on the same key, so change tracking would silently merge unrelated rows. pw.io.mysql.read therefore raises this ValueError at call time when any primary-key column is typed Optional, listing the offending names.","triggerScenarios":"Declaring a key column as Optional in the schema passed to pw.io.mysql.read, e.g. id: int | None = pw.column_definition(primary_key=True).","commonSituations":"Schemas generated from ORM models or introspection tools that mark everything nullable; defensive | None annotations copied from dataclass conventions; unioning schemas from heterogeneous sources.","solutions":["Change the primary-key column annotation from Optional[int] to int (MySQL PRIMARY KEY columns are NOT NULL by definition).","If NULLs actually occur in that column, it is not a real key — choose a different column or column set.","Keep Optional only on genuinely nullable non-key payload columns."],"exampleFix":"# before\nclass MySchema(pw.Schema):\n    id: int | None = pw.column_definition(primary_key=True)\n\n# after\nclass MySchema(pw.Schema):\n    id: int = pw.column_definition(primary_key=True)","handlingStrategy":"validation","validationCode":"import pathway as pw\n\ndtypes = schema._dtypes()\nnullable = [c for c in schema.primary_key_columns() if isinstance(dtypes[c], pw.dt.Optional)]\nassert not nullable, f\"Nullable PK columns: {nullable}\"","typeGuard":"import pathway as pw\n\ndef has_non_nullable_pks(schema) -> bool:\n    d = schema._dtypes()\n    return all(not isinstance(d[c], pw.dt.Optional) for c in schema.primary_key_columns())","tryCatchPattern":"try:\n    table = pw.io.mysql.read(conn, table_name, schema=MySchema)\nexcept ValueError as e:\n    if \"nullable\" in str(e):\n        raise SystemExit(\"Change PK annotations from Optional[...] to plain int/str\") from e\n    raise","preventionTips":["Never annotate primary-key columns Optional; MySQL PKs are NOT NULL by definition.","Audit introspection-generated schemas for blanket-nullable annotations.","Keep a lint rule or review checklist item: 'PK columns non-Optional'."],"tags":["mysql","primary-key","nullable","schema","pathway"],"backgroundTag":null,"analyzedSha":"fa2f74a4649b7c5908690cf60137263d8d80de5f","analyzedAt":"2026-08-15T01:48:17.006Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}