{"id":"685fe800ad6f81ba","repo":"sqlalchemy/alembic","slug":"individual-alter-column-constructs-not-supported-b","errorCode":null,"errorMessage":"Individual alter column constructs not supported by MySQL","messagePattern":"Individual alter column constructs not supported by MySQL","errorType":"exception","errorClass":"NotImplementedError","httpStatus":null,"severity":"error","filePath":"alembic/ddl/mysql.py","lineNumber":439,"sourceCode":"        if type_ is None:\n            raise util.CommandError(\n                \"All MySQL CHANGE/MODIFY COLUMN operations \"\n                \"require the existing type.\"\n            )\n\n        self.type_ = sqltypes.to_instance(type_)\n\n\nclass MySQLModifyColumn(MySQLChangeColumn):\n    pass\n\n\n@compiles(ColumnNullable, \"mysql\", \"mariadb\")\n@compiles(ColumnName, \"mysql\", \"mariadb\")\n@compiles(ColumnDefault, \"mysql\", \"mariadb\")\n@compiles(ColumnType, \"mysql\", \"mariadb\")\ndef _mysql_doesnt_support_individual(element, compiler, **kw):\n    raise NotImplementedError(\n        \"Individual alter column constructs not supported by MySQL\"\n    )\n\n\n@compiles(MySQLAlterDefault, \"mysql\", \"mariadb\")\ndef _mysql_alter_default(\n    element: MySQLAlterDefault, compiler: MySQLDDLCompiler, **kw\n) -> str:\n    return \"%s ALTER COLUMN %s %s\" % (\n        alter_table(compiler, element.table_name, element.schema),\n        format_column_name(compiler, element.column_name),\n        (\n            \"SET DEFAULT %s\" % format_server_default(compiler, element.default)\n            if element.default is not None\n            else \"DROP DEFAULT\"\n        ),\n    )\n","sourceCodeStart":421,"sourceCodeEnd":457,"githubUrl":"https://github.com/sqlalchemy/alembic/blob/44fb3450330204b222ff05135e1fbbbdb28c44db/alembic/ddl/mysql.py#L421-L457","documentation":"MySQL/MariaDB do not support per-attribute ALTER COLUMN clauses like 'ALTER COLUMN ... NULL', 'ALTER COLUMN ... DEFAULT', or standalone RENAME via SQLAlchemy's ColumnNullable/ColumnName/ColumnDefault/ColumnType constructs. Alembic's MySQL dialect compiles those individual alter constructs to an explicit NotImplementedError so that migrations do not silently emit no-op SQL.","triggerScenarios":"Calling op.alter_column('t', 'c', nullable=True) (or server_default=, new_column_name via ColumnName, or type_=) directly on MySQL/MariaDB outside of batch mode, where the operation translates into one of the disallowed individual ColumnNullable/ColumnDefault/ColumnType constructs.","commonSituations":"A migration that worked on PostgreSQL is run against MySQL; auto-generated alter_column on MySQL without batching; combining type change + nullability in separate calls.","solutions":["Use op.batch_alter_table('t') as batch_op: batch_op.alter_column('c', nullable=True, ...) which emits MySQL's single ALTER TABLE ... MODIFY COLUMN statement.","For a MySQL-native approach, issue op.execute('ALTER TABLE t MODIFY COLUMN c INT NULL') directly.","When autogenerating against MySQL, prefer batch_alter_table so all column changes collapse into one MODIFY."],"exampleFix":"// before\nop.alter_column('users', 'email', nullable=True)  # MySQL -> NotImplementedError\n// after\nwith op.batch_alter_table('users') as batch_op:\n    batch_op.alter_column('email', nullable=True)","handlingStrategy":"validation","validationCode":"from sqlalchemy import create_engine\ndialect_name = engine.dialect.name\nif dialect_name in (\"mysql\", \"mariadb\") and not _in_batch():\n    raise RuntimeError(\"Use batch_alter_table for alter_column on MySQL/MariaDB\")","typeGuard":"def needs_batch_for_alter(dialect_name) -> bool:\n    return dialect_name in (\"mysql\", \"mariadb\")","tryCatchPattern":null,"preventionTips":["Default to batch_alter_table for any alter_column on MySQL.","Run the test suite against the same dialect as production.","When autogenerating on MySQL, set the batch flag so MODIFY is emitted."],"tags":["mysql","mariadb","alter-column","batch-mode"],"analyzedSha":"44fb3450330204b222ff05135e1fbbbdb28c44db","analyzedAt":"2026-08-04T19:57:10.248Z","schemaVersion":2}