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

  1. Check the exact keyword name reported ('{k}') for a typo against the target method's documented signature.
  2. Remove the unsupported keyword argument, or move it to a location that accepts it (e.g. dialect_kwargs via the <dialect>_<arg> naming convention).
  3. If relying on a deprecated argument, consult the SQLAlchemy changelog/migration notes for the installed version and switch to the replacement.
  4. 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

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


AI-assisted analysis of sqlalchemy/sqlalchemy@d9b44cb731 (2026-08-01). Data as JSON: /data/errors/040d7ddbaa107b31.json. Report an issue: GitHub.