sqlalchemy/alembic · error · TypeError

'type' can be one of %s

Error message

'type' can be one of %s

What it means

Raised by SchemaObjects.generic_constraint() when the type_ argument is not one of the allowed keys ('foreignkey','primary','unique','check',None). The method maps type_ to a SQLAlchemy constraint constructor via a dict; an unknown type raises TypeError listing the valid values. generic_constraint is the internal factory used to render drop_constraint and similar ops.

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 44fb345033)

Solutions

  1. Pass one of the valid type_ values: 'foreignkey', 'primary', 'unique', 'check', or None.
  2. Build the op via the high-level API (op.drop_constraint(..., type_='foreignkey')) which documents the accepted strings.
  3. Validate the type_ string against the allowed set before calling generic_constraint().

Example fix

// before
schema_obj.generic_constraint('c', 'user', type_='foreign')  # raises TypeError

// after
schema_obj.generic_constraint('c', 'user', type_='foreignkey')
Defensive patterns

Strategy: validation

Validate before calling

VALID_CONSTRAINT_TYPES = {'foreignkey', 'primary', 'unique', 'check', None}

def validate_constraint_type(type_):
    if type_ not in VALID_CONSTRAINT_TYPES:
        raise ValueError(f'invalid constraint type {type_!r}; expected one of {VALID_CONSTRAINT_TYPES}')
    return type_

Type guard

def is_valid_constraint_type(type_) -> bool:
    return type_ in {'foreignkey', 'primary', 'unique', 'check', None}

Try / catch

try:
    schema_obj.generic_constraint(name, table, type_=t)
except TypeError as e:
    if "'type' can be one of" in str(e):
        # map/correct the type string
        schema_obj.generic_constraint(name, table, type_=normalized_t)
    else:
        raise

Prevention

When it happens

Trigger: Calling schema_obj.generic_constraint(name, table, type_='bogus') with an invalid type; a DropConstraintOp whose constraint_type is not normalized to one of the allowed values feeding into generic_constraint; typos like 'foreign' instead of 'foreignkey', 'uniq' instead of 'unique', 'pk' instead of 'primary'.

Common situations: Custom code that constructs constraint type strings manually; an op object built with an unsupported type string; version skew where a new constraint type isn't registered.

Related errors


AI-assisted analysis of sqlalchemy/alembic@44fb345033 (2026-08-04). Data as JSON: /data/errors/4808b48ab6281f33.json. Report an issue: GitHub.