{"record":{"id":"4808b48ab6281f33","repo":"sqlalchemy/alembic","slug":"type-can-be-one-of-s","errorCode":null,"errorMessage":"'type' can be one of %s","messagePattern":"'type' can be one of (.+?)","errorType":"validation","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"alembic/operations/schemaobj.py","lineNumber":179,"sourceCode":"        table_name: str,\n        type_: str | None,\n        schema: str | None = None,\n        **kw,\n    ) -> Any:\n        t = self.table(table_name, schema=schema)\n        types: dict[str | None, Any] = {\n            \"foreignkey\": lambda name: sa_schema.ForeignKeyConstraint(\n                [], [], name=name\n            ),\n            \"primary\": sa_schema.PrimaryKeyConstraint,\n            \"unique\": sa_schema.UniqueConstraint,\n            \"check\": lambda name: sa_schema.CheckConstraint(\"\", name=name),\n            None: sa_schema.Constraint,\n        }\n        try:\n            const = types[type_]\n        except KeyError as ke:\n            raise TypeError(\n                \"'type' can be one of %s\"\n                % \", \".join(sorted(repr(x) for x in types))\n            ) from ke\n        else:\n            const = const(name=name)\n            t.append_constraint(const)\n            return const\n\n    def metadata(self) -> MetaData:\n        kw = {}\n        if (\n            self.migration_context is not None\n            and \"target_metadata\" in self.migration_context.opts\n        ):\n            mt = self.migration_context.opts[\"target_metadata\"]\n            if hasattr(mt, \"naming_convention\"):\n                kw[\"naming_convention\"] = mt.naming_convention\n        return sa_schema.MetaData(**kw)","sourceCodeStart":161,"sourceCodeEnd":197,"githubUrl":"https://github.com/sqlalchemy/alembic/blob/5551b5d35f985c99cb8f1af2b3c526b050e4c059/alembic/operations/schemaobj.py#L161-L197","documentation":"Raised as TypeError by Operations.schema_obj.generic_constraint (schemaobj.py:176-182) when the type_ argument is not a key in the allowed types dict {foreignkey, primary, unique, check, None}. The KeyError is re-raised as a TypeError listing the valid values, telling the caller they passed an unrecognised constraint type.","triggerScenarios":"Calling op.drop_constraint('name', 'table', type_='fk') or type_='foreign' / type_='pk' / type_='index' (misspelled or wrong). The valid strings are exactly 'foreignkey','primary','unique','check' (and None). Anything else hits the KeyError branch.","commonSituations":"Typos and abbreviations in hand-written migrations; passing the SQLAlchemy constraint class name instead of the alembic short token; copy-paste from docs that use a different vocabulary.","solutions":["Use one of the exact tokens: 'foreignkey', 'primary', 'unique', or 'check' (case-sensitive).","For drop_constraint, pick type_ matching the constraint kind: foreign key -> 'foreignkey', primary key -> 'primary', unique -> 'unique', check -> 'check'.","If unsure, pass type_=None to drop a generic constraint by name."],"exampleFix":"// before\nop.drop_constraint('fk_orders_user', 'orders', type_='foreign')  # wrong\n// after\nop.drop_constraint('fk_orders_user', 'orders', type_='foreignkey')","handlingStrategy":"type-guard","validationCode":"# Validate the constraint type token before passing it to op.drop_constraint.\nVALID_TYPES = {'foreignkey', 'primary', 'unique', 'check', None}\n\ndef drop_constraint_safe(name, table, type_):\n    if type_ not in VALID_TYPES:\n        raise ValueError(\n            f'Invalid constraint type {type_!r}; expected one of {sorted(t for t in VALID_TYPES if t)}'\n        )\n    op.drop_constraint(name, table, type_=type_)","typeGuard":"from typing import Literal, get_args\n\nConstraintType = Literal['foreignkey', 'primary', 'unique', 'check']\n\ndef is_valid_constraint_type(t: str | None) -> bool:\n    return t is None or t in get_args(ConstraintType)","tryCatchPattern":null,"preventionTips":["Memorise the four valid tokens: foreignkey, primary, unique, check.","Add a unit test that asserts constraint type strings against the allowed set.","Use a Literal type in wrapper functions to catch typos at type-check time."],"tags":["alembic","constraints","validation","database-migration"],"backgroundTag":null,"analyzedSha":"5551b5d35f985c99cb8f1af2b3c526b050e4c059","analyzedAt":"2026-08-11T01:38:46.612Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}