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
Raised in `_apply_column_actions` when a state subkey encountered during column sync does not start with the expected `_COL_SUBKEY_PREFIX`. This is an internal format check on the target-state keys stored between runs; column subkeys must be prefixed so column actions can be distinguished from other subkey kinds (like the pgvector extension subkey).
Source
Thrown at python/cocoindex/connectors/postgres/_target.py:1125
self,
conn: asyncpg.pool.PoolConnectionProxy[asyncpg.Record],
key: _TableKey,
schema: TableSchema[Any],
column_actions: dict[str, statediff.DiffAction],
) -> None:
qualified_name = _qualified_table_name(key.table_name, key.pg_schema_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 sub_key == _EXT_PGVECTOR_SUBKEY:
if action != "delete":
await self._ensure_pgvector_extension(conn)
continue
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":
await conn.execute(
f'ALTER TABLE {qualified_name} DROP COLUMN IF EXISTS "{col_name}"'
)
continue
desired_col = non_pk_col_by_name.get(col_name)
if desired_col is None:
# If the desired schema no longer mentions this column, treat
# it as a no-op here; "delete" should have been emitted.View on GitHub (pinned to e84aa99b32)
Solutions
- Upgrade the library cleanly and re-create/re-sync the table target (drop the stale target state) so subkeys are rewritten in the current format.
- Clear the stored component/target state for this component path and run a full update.
- If reproducible on the latest version, file a bug with the offending subkey value from the message.
Defensive patterns
Strategy: fallback
Validate before calling
# check library version consistency across the environment
import cocoindex, importlib.metadata as im
assert im.version("cocoindex") == cocoindex.__version__ Try / catch
try:
await app.update()
except ValueError as e:
if "Unexpected column subkey format" in str(e):
logger.error("Stale target state after upgrade; recreate table target")
else:
raise Prevention
- Upgrade cocoindex atomically across all services that share state.
- Recreate target states after major version upgrades.
- Never hand-edit stored engine state.
When it happens
Trigger: A stale or corrupted state entry for the table target whose subkey isn't a recognized column subkey — typically after upgrading the library when the internal subkey scheme changed, or manual tampering with stored state.
Common situations: Upgrading cocoindex across versions that changed internal state key formats and then syncing a previously-created table; copying state between environments; mixing connector versions in a cluster.
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
- asyncpg is required to use the PostgreSQL source connector.
- {identifier_type} cannot be empty
- Invalid {identifier_type}: '{name}'. Must start with a lette
- Column '{column}' has PostgreSQL type '{pg_type}', which is
- Unsupported pgvector metric '{metric}' for PostgreSQL type '
AI-assisted analysis of cocoindex-io/cocoindex@e84aa99b32 (2026-09-08).
Data as JSON: /api/errors/b49e4f65b609b4e7.
Report an issue: GitHub.