{"record":{"id":"566a76f2f3f7b41f","repo":"cocoindex-io/cocoindex","slug":"sqlite-primary-key-column-pk-r-cannot-be-none","errorCode":null,"errorMessage":"SQLite primary key column {pk!r} cannot be None","messagePattern":"SQLite primary key column (.+?) cannot be None","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"python/cocoindex/connectors/sqlite/_target.py","lineNumber":1094,"sourceCode":"\n    def declare_row(self: \"TableTarget[RowT]\", *, row: RowT) -> None:\n        \"\"\"\n        Declare a row to be upserted to this table.\n\n        Args:\n            row: A row object (dict, dataclass, NamedTuple, or Pydantic model).\n                 Must include all primary key columns with non-None values.\n                 Dict rows may omit nullable non-primary-key columns; omitted values\n                 are written as NULL.\n        \"\"\"\n        row_dict = self._row_to_dict(row)\n        pk_values: list[Any] = []\n        for pk in self._table_schema.primary_key:\n            if isinstance(row, dict) and pk not in row:\n                raise ValueError(f\"SQLite row is missing primary key column {pk!r}\")\n            pk_value = row_dict[pk]\n            if pk_value is None:\n                raise ValueError(f\"SQLite primary key column {pk!r} cannot be None\")\n            pk_values.append(pk_value)\n        coco.declare_target_state(\n            self._provider.target_state(tuple(pk_values), row_dict)\n        )\n\n    def _row_to_dict(self, row: RowT) -> dict[str, Any]:\n        \"\"\"\n        Convert a row (dict or object) into dict[str, Any] using the schema columns,\n        and apply column encoders for both dict and object inputs.\n        \"\"\"\n        out: dict[str, Any] = {}\n        for col_name, col in self._table_schema.columns.items():\n            if isinstance(row, dict):\n                value = row.get(col_name)\n            else:\n                value = getattr(row, col_name)\n\n            if value is not None and col.encoder is not None:","sourceCodeStart":1076,"sourceCodeEnd":1112,"githubUrl":"https://github.com/cocoindex-io/cocoindex/blob/e84aa99b3292c5270a4b313b2a7137ad9ce8ab3b/python/cocoindex/connectors/sqlite/_target.py#L1076-L1112","documentation":"Primary key values must be non-NULL because they form the target-state identity of a row. `declare_row` raises `ValueError` when any primary key column value is `None`, including non-dict (dataclass/NamedTuple/Pydantic) rows whose pk field was left unset.","triggerScenarios":"Declaring a row where a primary-key field is `None` — e.g. an optional dataclass field defaulting to `None`, or a dict with `\"id\": None`; also reached for non-dict rows since the check applies to `row_dict[pk]` regardless of row kind.","commonSituations":"Optional pk fields on dataclasses (`id: int | None = None`) left unset; records built from upstream data where the id failed to populate; auto-increment mental model (SQLite rowid) that does not apply because the engine needs the key up front.","solutions":["Provide a concrete non-None value for every primary key column before declaring the row","Make the pk field required in the record type so it cannot default to None","Generate ids yourself (uuid/counter) before calling `declare_row`"],"exampleFix":"// before\n@dataclass\nclass Row:\n    id: int | None = None\ntarget.declare_row(Row())\n// after\n@dataclass\nclass Row:\n    id: int\ntarget.declare_row(Row(id=uuid4().int))","handlingStrategy":"validation","validationCode":"for pk in primary_keys:\n    if row[pk] is None:\n        raise ValueError(f\"{pk} must be non-None before declare_row\")","typeGuard":"def pks_present(row: dict, pks: list[str]) -> bool:\n    return all(row.get(pk) is not None for pk in pks)","tryCatchPattern":"try:\n    target.declare_row(row)\nexcept ValueError as e:\n    if \"cannot be None\" in e.args[0]:\n        row[pk_field] = generate_id()\n    else:\n        raise","preventionTips":["Declare pk fields as required (non-Optional) in record types","Generate ids (uuid/nanoid) before declaring rows — there is no auto-increment in this model","Reject None pks at the boundary where rows are produced"],"tags":["sqlite","primary-key","null","validation"],"backgroundTag":"null-argument","analyzedSha":"e84aa99b3292c5270a4b313b2a7137ad9ce8ab3b","analyzedAt":"2026-09-08T15:59:19.997Z","contentChangedAt":"2026-09-08T15:59:19.997Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}