sqlalchemy/sqlalchemy · error · TypeError
{methname} got an unexpected keyword argument '{k}'
Error message
{methname} got an unexpected keyword argument '{k}' What it means
Raised by the SQLAlchemy internal helper _unexpected_kw() in sql/_typing.py, which is a thin shim that converts an unexpected leftover **kw dict into a standard Python TypeError. Many SQLAlchemy public/semi-public APIs accept **kw purely for PEP-484 typing/static-analysis reasons but do not actually consume arbitrary keyword arguments at runtime; if any kwargs remain unprocessed, this helper raises. It mirrors the behavior of Python's native 'unexpected keyword argument' error for functions whose signatures use a catch-all **kw.
Source
Thrown at lib/sqlalchemy/sql/_typing.py:415
def is_has_clause_element(s: object) -> TypeGuard[_HasClauseElement[Any]]:
return hasattr(s, "__clause_element__")
def is_insert_update(c: ClauseElement) -> TypeGuard[ValuesBase]:
return c.is_dml and (c.is_insert or c.is_update) # type: ignore[attr-defined] # noqa: E501
def _no_kw() -> exc.ArgumentError:
return exc.ArgumentError(
"Additional keyword arguments are not accepted by this "
"function/method. The presence of **kw is for pep-484 typing purposes"
)
def _unexpected_kw(methname: str, kw: Dict[str, Any]) -> NoReturn:
k = list(kw)[0]
raise TypeError(f"{methname} got an unexpected keyword argument '{k}'")
@overload
def Nullable(
val: "SQLCoreOperations[_T]",
) -> "SQLCoreOperations[Optional[_T]]": ...
@overload
def Nullable(
val: roles.ExpressionElementRole[_T],
) -> roles.ExpressionElementRole[Optional[_T]]: ...
@overload
def Nullable(val: Type[_T]) -> Type[Optional[_T]]: ...
View on GitHub (pinned to d9b44cb731)
Solutions
- Check the exact keyword name reported ('{k}') for a typo against the target method's documented signature.
- Remove the unsupported keyword argument, or move it to a location that accepts it (e.g. dialect_kwargs via the <dialect>_<arg> naming convention).
- If relying on a deprecated argument, consult the SQLAlchemy changelog/migration notes for the installed version and switch to the replacement.
- Verify you are not passing generic **kwargs through from your own wrapper that were intended for a different function.
Example fix
// before stmt = select(User).options(some_loader(User.addresses, invalid_kw=True)) // after stmt = select(User).options(some_loader(User.addresses))
Defensive patterns
Strategy: type-guard
Validate before calling
import inspect
def validate_kwargs_accepted(func, *args, **kwargs):
"""Call before invoking func(**kw) to guarantee no 'unexpected keyword
argument' TypeError is raised by SQLAlchemy's _unexpected_kw guard."""
sig = inspect.signature(func)
accepts_var_kw = any(
p.kind is inspect.Parameter.VAR_KEYWORD for p in sig.parameters.values()
)
if accepts_var_kw:
return # cannot statically reject; SQLAlchemy will reject unknown kw
allowed = {
name for name, p in sig.parameters.items()
if p.kind in (p.POSITIONAL_OR_KEYWORD, p.KEYWORD_ONLY)
}
unknown = set(kwargs) - allowed
if unknown:
raise TypeError(
f"{func.__qualname__} does not accept kwargs: {sorted(unknown)}"
) Type guard
import inspect
def accepts_keyword(func, key: str) -> bool:
"""Type-guard: True if func genuinely accepts keyword `key`."""
try:
sig = inspect.signature(func)
except (TypeError, ValueError):
return True # builtin/C-funcs: assume permissive
params = sig.parameters
if any(p.kind is p.VAR_KEYWORD for p in params.values()):
# SQLAlchemy functions with **kw often reject via _no_kw/_unexpected_kw,
# so treat VAR_KEYWORD as NON-permissive here.
return False
return key in params and params[key].kind in (
params[key].POSITIONAL_OR_KEYWORD, params[key].KEYWORD_ONLY
) Try / catch
try:
result = sa_func(known_arg=1, bogus_arg=2)
except TypeError as e:
if "unexpected keyword argument" in str(e):
# strip the offending kwarg and retry, or surface a clear error
raise TypeError(f"Unsupported kwarg passed to SQLAlchemy API: {e}") from e
raise Prevention
- Treat SQLAlchemy **kw parameters shown in signatures as type-check-only stubs: they reject at runtime via _no_kw/_unexpected_kw, so do not forward arbitrary kwargs into them.
- When wrapping SQLAlchemy functions, filter kwargs through inspect.signature rather than passing **kwargs blindly.
- Keep mypy strict and let the typed SQLAlchemy 2.0 stubs reject unknown kwargs at static-analysis time.
When it happens
Trigger: Calling a SQLAlchemy API that uses a typing-only **kw parameter and passing a keyword it does not actually accept, e.g. passing an unknown kwarg to a method that lists **kw for type overloads. The helper is invoked internally when SQLAlchemy detects leftover kwargs that should have been consumed, e.g. through helper code paths that forward kwargs and then call _unexpected_kw(methname, remaining_kw).
Common situations: Migrating code where method signatures changed between minor SQLAlchemy releases and a previously-tolerated kwarg is now rejected; passing dialect-specific or deprecated kwargs to core methods; static type stubs suggesting an argument that the runtime does not honor; typos in keyword names passed to ORM/Core builder methods.
Related errors
- Annotation {raw_annotation} for attribute '{cls.__name__}.{n
- Invalid argument(s) %s sent to create_engine(), using config
- Query dictionary keys must be strings
- %s objects are unhashable
- Use of the {self._mapper_property_name()!r} construct inside
AI-assisted analysis of sqlalchemy/sqlalchemy@d9b44cb731 (2026-08-01).
Data as JSON: /data/errors/040d7ddbaa107b31.json.
Report an issue: GitHub.