{"id":"b0d2938a8131b6a9","repo":"sqlalchemy/alembic","slug":"duplicate-table-keys-across-multiple-metadata-obje","errorCode":null,"errorMessage":"Duplicate table keys across multiple MetaData objects: %s","messagePattern":"Duplicate table keys across multiple MetaData objects: (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"alembic/autogenerate/api.py","lineNumber":513,"sourceCode":"        return result\n\n    @util.memoized_property\n    def table_key_to_table(self) -> dict[str, Table]:\n        \"\"\"Return an aggregate  of the :attr:`.MetaData.tables` dictionaries.\n\n        The :attr:`.MetaData.tables` collection is a dictionary of table key\n        to :class:`.Table`; this method aggregates the dictionary across\n        multiple :class:`.MetaData` objects into one dictionary.\n\n        Duplicate table keys are **not** supported; if two :class:`.MetaData`\n        objects contain the same table key, an exception is raised.\n\n        \"\"\"\n        result: dict[str, Table] = {}\n        for m in util.to_list(self.metadata):\n            intersect = set(result).intersection(set(m.tables))\n            if intersect:\n                raise ValueError(\n                    \"Duplicate table keys across multiple \"\n                    \"MetaData objects: %s\"\n                    % (\", \".join('\"%s\"' % key for key in sorted(intersect)))\n                )\n\n            result.update(m.tables)\n        return result\n\n\nclass RevisionContext:\n    \"\"\"Maintains configuration and state that's specific to a revision\n    file generation operation.\"\"\"\n\n    generated_revisions: list[MigrationScript]\n    process_revision_directives: ProcessRevisionDirectiveFn | None\n\n    def __init__(\n        self,","sourceCodeStart":495,"sourceCodeEnd":531,"githubUrl":"https://github.com/sqlalchemy/alembic/blob/44fb3450330204b222ff05135e1fbbbdb28c44db/alembic/autogenerate/api.py#L495-L531","documentation":"Alembic aggregates multiple MetaData objects passed to configure() into one table-key map; the table_key_to_table property refuses to silently merge two MetaData objects that declare the same (schema, table_name) key, because doing so would be ambiguous. This guards against accidentally wiring the same model metadata in twice, or two metadata sets that overlap.","triggerScenarios":"Passing a list/tuple of MetaData objects to EnvironmentContext.configure(target_metadata=[meta_a, meta_b]) where meta_a and meta_b both define a Table with the same key (e.g. both define 'users', or 'myschema.users').","commonSituations":"App registers the same declarative Base.metadata in two separate MetaData groupings; a plugin or shared library contributes a table that the app also defines; a refactor split metadata but left duplicate declarations.","solutions":["De-duplicate: ensure each table is declared in exactly one MetaData and pass the union metadata once.","If duplicates are intentional (e.g. per-schema splits), rename one table or assign distinct schemas so the keys differ.","Pass a single combined MetaData that already holds all tables instead of a list with overlap."],"exampleFix":"// before\ncontext.configure(target_metadata=[base.metadata, plugin.metadata])\n# both define Table('users', ...) -> ValueError\n// after\ncontext.configure(target_metadata=base.metadata)  # plugin tables also attached here","handlingStrategy":"validation","validationCode":"from sqlalchemy import MetaData\nmetas = [m for m in (target_metadata if isinstance(target_metadata, (list, tuple)) else [target_metadata])]\nseen, dupes = set(), set()\nfor m in metas:\n    for k in m.tables:\n        (dupes if k in seen else seen).add(k)\nassert not dupes, f\"Duplicate table keys across MetaData objects: {sorted(dupes)}\"","typeGuard":"def has_unique_table_keys(metas) -> bool:\n    keys = set()\n    for m in metas:\n        inter = keys.intersection(m.tables)\n        if inter:\n            return False\n        keys.update(m.tables)\n    return True","tryCatchPattern":null,"preventionTips":["Pass a single declarative Base.metadata rather than a list.","If splitting metadata, ensure each table lives in exactly one MetaData.","Add a unit test that asserts table key uniqueness before configure()."],"tags":["autogenerate","metadata","configuration"],"analyzedSha":"44fb3450330204b222ff05135e1fbbbdb28c44db","analyzedAt":"2026-08-04T19:57:10.248Z","schemaVersion":2}