cocoindex-io/cocoindex · error · RuntimeError

Failed to add column {col_name!r} to SQLite table {table_nam

Error message

Failed to add column {col_name!r} to SQLite table {table_name!r}: {e}

What it means

When applying an `add` column action, `_apply_column_actions` runs `ALTER TABLE ... ADD COLUMN`. If SQLite raises `OperationalError` for any reason other than 'duplicate column name' (which is tolerated as idempotent re-run), the error is wrapped in a `RuntimeError` naming the column and table.

Source

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

        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.
            continue

        if action in ("insert", "upsert"):
            # SQLite supports ADD COLUMN
            nullable = "" if desired_col.nullable else " NOT NULL"
            try:
                conn.execute(
                    f"ALTER TABLE {qualified_name} "
                    f'ADD COLUMN "{col_name}" {desired_col.type}{nullable}'
                )
            except sqlite3.OperationalError as e:
                # Only ignore if column already exists (e.g. upsert / idempotent re-run)
                if "duplicate column name" in str(e).lower():
                    pass
                else:
                    raise RuntimeError(
                        f"Failed to add column {col_name!r} to SQLite table {table_name!r}: {e}"
                    ) from e
            continue

        if action == "replace":
            # SQLite doesn't support ALTER COLUMN TYPE directly.
            # For type changes, attempt to drop and re-add column.
            try:
                conn.execute(f'ALTER TABLE {qualified_name} DROP COLUMN "{col_name}"')
            except sqlite3.OperationalError:
                pass
            nullable = "" if desired_col.nullable else " NOT NULL"
            try:
                conn.execute(
                    f"ALTER TABLE {qualified_name} "
                    f'ADD COLUMN "{col_name}" {desired_col.type}{nullable}'
                )
            except sqlite3.OperationalError as e:

View on GitHub (pinned to e84aa99b32)

Solutions

  1. Read the wrapped SQLite message (`{e}`) to identify the underlying ALTER TABLE failure
  2. Make the new column nullable or provide a default so SQLite's ADD COLUMN restrictions are satisfied
  3. Fix the column type mapping (SqliteType / VectorSchemaProvider override) to a valid SQLite type
  4. Ensure no concurrent process is mutating the same table during sync

Example fix

// before (column override forcing invalid/strict add)
column_overrides={"embedding": sqlite.SqliteType.FLOAT_VECTOR(dim=0)}
// after
column_overrides={"embedding": sqlite.VectorSchemaProvider(dim=768)}
Defensive patterns

Strategy: try-catch

Validate before calling

# validate override types before sync
for name, ov in column_overrides.items():
    assert ov is not None and name in schema_fields

Try / catch

try:
    await app.update()
except RuntimeError as e:
    if str(e).startswith("Failed to add column"):
        log_sqlite_detail(e.__cause__)
        # fix column type/nullability, then retry
    else:
        raise

Prevention

When it happens

Trigger: Adding a column whose SQLite type is invalid or unsupported; attempting to add a non-nullable PRIMARY KEY/UNIQUE column (SQLite restriction); the table name colliding with an internal alias or a reserved name; a concurrently dropped table.

Common situations: Schema evolution where the new column's derived SqliteType is malformed (e.g. a bad vector dimension); adding a column declared `nullable=False` with a PRIMARY KEY constraint; running two syncs concurrently on the same database file.

Related errors


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