cocoindex-io/cocoindex · error · ValueError

Unexpected column subkey format: {sub_key!r}, expected to st

Error message

Unexpected column subkey format: {sub_key!r}, expected to start with {_COL_SUBKEY_PREFIX!r}

What it means

During incremental table sync, column-level actions are keyed by sub-keys that must be prefixed with `_COL_SUBKEY_PREFIX` (identifying them as column actions). `_apply_column_actions` raises `ValueError` when it encounters a sub-key with an unexpected format, protecting against internal state mismatches or hand-crafted table actions.

Source

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

def _apply_column_actions(
    conn: sqlite3.Connection,
    table_name: str,
    schema: TableSchema[Any],
    column_actions: dict[str, statediff.DiffAction],
) -> None:
    """Apply column-level changes to the table.

    Note: SQLite has limited ALTER TABLE support. Adding columns is supported,
    but modifying or dropping columns requires recreating the table (in older SQLite).
    SQLite 3.35.0+ supports DROP COLUMN.
    """
    qualified_name = _qualified_table_name(table_name)
    pk_cols = set(schema.primary_key)
    non_pk_col_by_name = {n: c for n, c in schema.columns.items() if n not in pk_cols}

    for sub_key, action in column_actions.items():
        if not sub_key.startswith(_COL_SUBKEY_PREFIX):
            raise ValueError(
                f"Unexpected column subkey format: {sub_key!r}, expected to start with {_COL_SUBKEY_PREFIX!r}"
            )
        col_name = sub_key[len(_COL_SUBKEY_PREFIX) :]

        # Defensive: we never ALTER PK columns here.
        if col_name in pk_cols:
            continue

        if action == "delete":
            # SQLite 3.35.0+ supports DROP COLUMN
            try:
                conn.execute(f'ALTER TABLE {qualified_name} DROP COLUMN "{col_name}"')
            except sqlite3.OperationalError:
                # Older SQLite doesn't support DROP COLUMN - silently skip
                pass
            continue

        desired_col = non_pk_col_by_name.get(col_name)

View on GitHub (pinned to e84aa99b32)

Solutions

  1. This indicates an internal invariant violation — report it with the failing action keys and cocoindex version
  2. Re-sync the affected table from scratch (drop the state so actions are regenerated by the current version)
  3. If writing custom connector code, prefix column sub-keys with the library's `_COL_SUBKEY_PREFIX` constant rather than raw names
Defensive patterns

Strategy: try-catch

Try / catch

try:
    await app.update()
except ValueError as e:
    if "Unexpected column subkey format" in str(e):
        report_bug_with_version()  # internal invariant violation
    raise

Prevention

When it happens

Trigger: An internal bug or stale stored state produces column action keys without the expected prefix; users manually constructing or tampering with table action dictionaries passed into the apply path.

Common situations: Upgrading cocoindex across versions where persisted action/plan formats changed; custom connector code that builds its own action dict with bare column names instead of prefixed sub-keys.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


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