sqlalchemy/alembic · error · TypeError
'type' can be one of
Error message
'type' can be one of %s
What it means
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.
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.
Example fix
// before
op.drop_constraint('fk_orders_user', 'orders', type_='foreign') # wrong
// after
op.drop_constraint('fk_orders_user', 'orders', type_='foreignkey') Defensive patterns
Strategy: type-guard
Validate before calling
# Validate the constraint type token before passing it to op.drop_constraint.
VALID_TYPES = {'foreignkey', 'primary', 'unique', 'check', None}
def drop_constraint_safe(name, table, type_):
if type_ not in VALID_TYPES:
raise ValueError(
f'Invalid constraint type {type_!r}; expected one of {sorted(t for t in VALID_TYPES if t)}'
)
op.drop_constraint(name, table, type_=type_) Type guard
from typing import Literal, get_args
ConstraintType = Literal['foreignkey', 'primary', 'unique', 'check']
def is_valid_constraint_type(t: str | None) -> bool:
return t is None or t in get_args(ConstraintType) Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- constraint cannot be produced; original constraint is not…
- Constraint must have a name
- No such constraint
- Can't change down_revision on a refresh operation.
- Can't drop table in batch mode
AI-assisted analysis of sqlalchemy/alembic@5551b5d35f (2026-08-11).
Data as JSON: /api/errors/4808b48ab6281f33.
Report an issue: GitHub.
Appendix: source
Thrown at alembic/operations/schemaobj.py:179
table_name: str,
type_: str | None,
schema: str | None = None,
**kw,
) -> Any:
t = self.table(table_name, schema=schema)
types: dict[str | None, Any] = {
"foreignkey": lambda name: sa_schema.ForeignKeyConstraint(
[], [], name=name
),
"primary": sa_schema.PrimaryKeyConstraint,
"unique": sa_schema.UniqueConstraint,
"check": lambda name: sa_schema.CheckConstraint("", name=name),
None: sa_schema.Constraint,
}
try:
const = types[type_]
except KeyError as ke:
raise TypeError(
"'type' can be one of %s"
% ", ".join(sorted(repr(x) for x in types))
) from ke
else:
const = const(name=name)
t.append_constraint(const)
return const
def metadata(self) -> MetaData:
kw = {}
if (
self.migration_context is not None
and "target_metadata" in self.migration_context.opts
):
mt = self.migration_context.opts["target_metadata"]
if hasattr(mt, "naming_convention"):
kw["naming_convention"] = mt.naming_convention
return sa_schema.MetaData(**kw)View on GitHub (pinned to 5551b5d35f)