sqlalchemy/alembic · error · NotImplementedError

Individual alter column constructs not supported by MySQL

Error message

Individual alter column constructs not supported by MySQL

What it means

MySQL/MariaDB compilation of ColumnNullable, ColumnName, ColumnDefault, or ColumnType raises NotImplementedError. MySQL does not support individual ALTER COLUMN sub-operations; it requires a single CHANGE COLUMN or MODIFY COLUMN that restates the full column definition. Alembic emits MySQL-specific constructs (MySQLModifyColumn) instead, so hitting the generic ones means an unsupported path was reached.

Solutions

  1. Use op.alter_column() which Alembic translates to CHANGE/MODIFY COLUMN on MySQL, restating nullable/type/default together.
  2. When altering a MySQL column, supply existing_type (and existing_nullable/existing_server_default) so the full MODIFY spec can be generated.
  3. Avoid compiling bare ColumnNullable/ColumnType constructs directly for the MySQL dialect.

Example fix

# before (unsupported on MySQL)
# a bare alter that loses full column info

# after: alter_column restates full definition
op.alter_column('t', 'c', existing_type=sa.Integer(),
               type_=sa.String(50), nullable=False)
Defensive patterns

Strategy: validation

Validate before calling

def alter_column_mysql(op, table, col, existing_type, **kw):
    # always pass existing_type so MODIFY COLUMN can restate the definition
    op.alter_column(table, col, existing_type=existing_type, **kw)

Type guard

def has_existing_type(kw: dict) -> bool:
    return kw.get('existing_type') is not None

Prevention

When it happens

Trigger: Custom code that directly compiles a bare ColumnNullable/ColumnName/ColumnDefault/ColumnType against the mysql or mariadb dialect; or an operations path that bypasses Alembic's alter_column MySQL rewrite and feeds the generic construct to the compiler.

Common situations: Third-party dialect plugins or custom ops that build standalone alter-column constructs; calling op.alter_column with a combination that Alembic's MySQL impl fails to translate into MySQLChangeColumn.

Related errors


AI-assisted analysis of sqlalchemy/alembic@5551b5d35f (2026-08-11). Data as JSON: /api/errors/685fe800ad6f81ba. Report an issue: GitHub.

Appendix: source

Thrown at alembic/ddl/mysql.py:439

        if type_ is None:
            raise util.CommandError(
                "All MySQL CHANGE/MODIFY COLUMN operations "
                "require the existing type."
            )

        self.type_ = sqltypes.to_instance(type_)


class MySQLModifyColumn(MySQLChangeColumn):
    pass


@compiles(ColumnNullable, "mysql", "mariadb")
@compiles(ColumnName, "mysql", "mariadb")
@compiles(ColumnDefault, "mysql", "mariadb")
@compiles(ColumnType, "mysql", "mariadb")
def _mysql_doesnt_support_individual(element, compiler, **kw):
    raise NotImplementedError(
        "Individual alter column constructs not supported by MySQL"
    )


@compiles(MySQLAlterDefault, "mysql", "mariadb")
def _mysql_alter_default(
    element: MySQLAlterDefault, compiler: MySQLDDLCompiler, **kw
) -> str:
    return "%s ALTER COLUMN %s %s" % (
        alter_table(compiler, element.table_name, element.schema),
        format_column_name(compiler, element.column_name),
        (
            "SET DEFAULT %s" % format_server_default(compiler, element.default)
            if element.default is not None
            else "DROP DEFAULT"
        ),
    )

View on GitHub (pinned to 5551b5d35f)