cocoindex-io/cocoindex · error · ValueError

SQLite row is missing primary key column {pk!r}

Error message

SQLite row is missing primary key column {pk!r}

What it means

`RowTarget.declare_row` converts the row to a dict and reads every primary-key column to build the target state key. When the row is a plain `dict` that lacks one of the schema's primary key column names, a `ValueError` is raised naming the missing key, because the row cannot be identified in the target state.

Source

Thrown at python/cocoindex/connectors/sqlite/_target.py:1091

    ) -> None:
        self._provider = provider
        self._table_schema = table_schema

    def declare_row(self: "TableTarget[RowT]", *, row: RowT) -> None:
        """
        Declare a row to be upserted to this table.

        Args:
            row: A row object (dict, dataclass, NamedTuple, or Pydantic model).
                 Must include all primary key columns with non-None values.
                 Dict rows may omit nullable non-primary-key columns; omitted values
                 are written as NULL.
        """
        row_dict = self._row_to_dict(row)
        pk_values: list[Any] = []
        for pk in self._table_schema.primary_key:
            if isinstance(row, dict) and pk not in row:
                raise ValueError(f"SQLite row is missing primary key column {pk!r}")
            pk_value = row_dict[pk]
            if pk_value is None:
                raise ValueError(f"SQLite primary key column {pk!r} cannot be None")
            pk_values.append(pk_value)
        coco.declare_target_state(
            self._provider.target_state(tuple(pk_values), row_dict)
        )

    def _row_to_dict(self, row: RowT) -> dict[str, Any]:
        """
        Convert a row (dict or object) into dict[str, Any] using the schema columns,
        and apply column encoders for both dict and object inputs.
        """
        out: dict[str, Any] = {}
        for col_name, col in self._table_schema.columns.items():
            if isinstance(row, dict):
                value = row.get(col_name)
            else:

View on GitHub (pinned to e84aa99b32)

Solutions

  1. Ensure the dict contains every primary key column with the exact name from the schema
  2. Fix typos in the row dict keys
  3. Update the `primary_key` argument to match the actual keys your rows provide

Example fix

// before
target.declare_row({"doc_id": 1, "text": "hi"})  # schema pk is "id"
// after
target.declare_row({"id": 1, "text": "hi"})
Defensive patterns

Strategy: validation

Validate before calling

required_pks = {"id"}  # schema.primary_key
missing = required_pks - row.keys()
assert not missing, f"row missing pk fields: {missing}"

Type guard

def has_all_pks(row: dict, pks: list[str]) -> bool:
    return all(pk in row for pk in pks)

Try / catch

try:
    target.declare_row(row_dict)
except ValueError as e:
    if e.args[0].startswith("SQLite row is missing primary key"):
        fix_row_keys(row_dict)
    else:
        raise

Prevention

When it happens

Trigger: Calling `target.declare_row({...})` with a dict whose keys do not include every column listed in the table's `primary_key` (e.g. typo'd key name, key omitted, primary_key config changed after the rows were built).

Common situations: Renaming a dataclass field while `primary_key=[...]` still references the old name; building row dicts dynamically and dropping the id field; changing `primary_key` in `table_target(...)` without updating the produced rows.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


AI-assisted analysis of cocoindex-io/cocoindex@e84aa99b32 (2026-09-08). Data as JSON: /api/errors/f5303dd16f5d0873. Report an issue: GitHub.