sqlalchemy/alembic · error · NotImplementedError

No support for ALTER of constraints in SQLite dialect. Pleas

Error message

No support for ALTER of constraints in SQLite dialect. Please refer to the batch mode feature which allows for SQLite migrations using a copy-and-move strategy.

What it means

SQLite cannot ALTER TABLE to add most constraints (it lacks ADD CONSTRAINT). Alembic's SQLite dialect distinguishes implicit constraints (which it warns and skips) from explicit ones (which have _create_rule set to None and would produce invalid SQL); explicit adds raise with a pointer to batch mode, which recreates the table via copy-and-move.

Source

Thrown at alembic/ddl/sqlite.py:78

                if isinstance(
                    col.server_default, schema.DefaultClause
                ) and isinstance(col.server_default.arg, sql.ClauseElement):
                    return True
                elif (
                    isinstance(col.server_default, Computed)
                    and col.server_default.persisted
                ):
                    return True
            elif op[0] not in ("create_index", "drop_index"):
                return True
        else:
            return False

    def add_constraint(self, const: Constraint, **kw: Any):
        # attempt to distinguish between an
        # auto-gen constraint and an explicit one
        if const._create_rule is None:
            raise NotImplementedError(
                "No support for ALTER of constraints in SQLite dialect. "
                "Please refer to the batch mode feature which allows for "
                "SQLite migrations using a copy-and-move strategy."
            )
        elif const._create_rule(self):
            util.warn(
                "Skipping unsupported ALTER for "
                "creation of implicit constraint. "
                "Please refer to the batch mode feature which allows for "
                "SQLite migrations using a copy-and-move strategy."
            )

    def drop_constraint(self, const: Constraint, **kw: Any):
        if const._create_rule is None:
            raise NotImplementedError(
                "No support for ALTER of constraints in SQLite dialect. "
                "Please refer to the batch mode feature which allows for "
                "SQLite migrations using a copy-and-move strategy."

View on GitHub (pinned to 44fb345033)

Solutions

  1. Wrap the operation in op.batch_alter_table('t') as batch_op: and use batch_op.create_foreign_key(...) etc.
  2. For new tables, declare the constraint inline in the CreateTable operation instead of adding it later.
  3. Set recreate='always' in batch_alter_table if auto-detection misfires.

Example fix

// before
op.create_foreign_key('fk_t_u', 't', 'u', ['u_id'], ['id'])  # SQLite -> NotImplementedError
// after
with op.batch_alter_table('t') as batch_op:
    batch_op.create_foreign_key('fk_t_u', 't', 'u', ['u_id'], ['id'])
Defensive patterns

Strategy: validation

Validate before calling

if engine.dialect.name == "sqlite":
    if not _in_batch():
        raise RuntimeError("SQLite cannot add constraints without batch mode")

Type guard

def is_sqlite(dialect) -> bool:
    return getattr(dialect, "name", "") == "sqlite"

Prevention

When it happens

Trigger: Calling op.create_foreign_key(...), op.create_unique_constraint(...), op.create_check_constraint(...), or op.create_primary_key(...) on SQLite outside of batch mode.

Common situations: A migration authored on PostgreSQL uses op.create_foreign_key and is run against SQLite in tests; a SQLite-first project that tries to add a constraint to an existing table.

Related errors


AI-assisted analysis of sqlalchemy/alembic@44fb345033 (2026-08-04). Data as JSON: /data/errors/3620ecdfc4730c76.json. Report an issue: GitHub.