{"record":{"id":"9e4d1e18481bce8d","repo":"cocoindex-io/cocoindex","slug":"unexpected-column-subkey-format-sub-key-r-expe-9e4d1e","errorCode":null,"errorMessage":"Unexpected column subkey format: {sub_key!r}, expected to start with {_COL_SUBKEY_PREFIX!r}","messagePattern":"Unexpected column subkey format: (.+?), expected to start with (.+?)","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"python/cocoindex/connectors/sqlite/_target.py","lineNumber":811,"sourceCode":"def _apply_column_actions(\n    conn: sqlite3.Connection,\n    table_name: str,\n    schema: TableSchema[Any],\n    column_actions: dict[str, statediff.DiffAction],\n) -> None:\n    \"\"\"Apply column-level changes to the table.\n\n    Note: SQLite has limited ALTER TABLE support. Adding columns is supported,\n    but modifying or dropping columns requires recreating the table (in older SQLite).\n    SQLite 3.35.0+ supports DROP COLUMN.\n    \"\"\"\n    qualified_name = _qualified_table_name(table_name)\n    pk_cols = set(schema.primary_key)\n    non_pk_col_by_name = {n: c for n, c in schema.columns.items() if n not in pk_cols}\n\n    for sub_key, action in column_actions.items():\n        if not sub_key.startswith(_COL_SUBKEY_PREFIX):\n            raise ValueError(\n                f\"Unexpected column subkey format: {sub_key!r}, expected to start with {_COL_SUBKEY_PREFIX!r}\"\n            )\n        col_name = sub_key[len(_COL_SUBKEY_PREFIX) :]\n\n        # Defensive: we never ALTER PK columns here.\n        if col_name in pk_cols:\n            continue\n\n        if action == \"delete\":\n            # SQLite 3.35.0+ supports DROP COLUMN\n            try:\n                conn.execute(f'ALTER TABLE {qualified_name} DROP COLUMN \"{col_name}\"')\n            except sqlite3.OperationalError:\n                # Older SQLite doesn't support DROP COLUMN - silently skip\n                pass\n            continue\n\n        desired_col = non_pk_col_by_name.get(col_name)","sourceCodeStart":793,"sourceCodeEnd":829,"githubUrl":"https://github.com/cocoindex-io/cocoindex/blob/e84aa99b3292c5270a4b313b2a7137ad9ce8ab3b/python/cocoindex/connectors/sqlite/_target.py#L793-L829","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["This indicates an internal invariant violation — report it with the failing action keys and cocoindex version","Re-sync the affected table from scratch (drop the state so actions are regenerated by the current version)","If writing custom connector code, prefix column sub-keys with the library's `_COL_SUBKEY_PREFIX` constant rather than raw names"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try:\n    await app.update()\nexcept ValueError as e:\n    if \"Unexpected column subkey format\" in str(e):\n        report_bug_with_version()  # internal invariant violation\n    raise","preventionTips":["Do not construct or mutate table action dicts manually","Avoid mixing cocoindex versions against the same database state; re-sync after upgrades","Pin the cocoindex version used to write and read persisted state"],"tags":["sqlite","internal","schema-migration"],"backgroundTag":"internal-invariant-violation","analyzedSha":"e84aa99b3292c5270a4b313b2a7137ad9ce8ab3b","analyzedAt":"2026-09-08T15:59:19.997Z","contentChangedAt":"2026-09-08T15:59:19.997Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}