astral-sh/ruff · info
Unknown keyword argument
Error message
Unknown keyword argument
What it means
Raised by `args_map` in the flake8-pytest-style unittest-assert rewriter when a keyword argument of an `assertX(...)` call is not present in the method's argument spec (`arg_spec()`). The rewriter can only rewrite calls whose keywords it recognizes as real parameters of the assertion method, so an unrecognized keyword aborts the fix generation while the PT009 diagnostic itself is still emitted.
Source
Thrown at crates/ruff_linter/src/rules/flake8_pytest_style/rules/unittest_assert.rs:248
fn args_map<'a>(
&'a self,
args: &'a [Expr],
keywords: &'a [Keyword],
) -> Result<FxHashMap<&'a str, &'a Expr>> {
// If we have variable-length arguments, abort.
if args.iter().any(Expr::is_starred_expr) || keywords.iter().any(|kw| kw.arg.is_none()) {
bail!("Variable-length arguments are not supported");
}
let arg_spec = self.arg_spec();
// If any of the keyword arguments are not in the argument spec, abort.
if keywords.iter().any(|kw| {
kw.arg
.as_ref()
.is_some_and(|kwarg_name| !arg_spec.contains(&kwarg_name.as_str()))
}) {
bail!("Unknown keyword argument");
}
// Generate a map from argument name to value.
let mut args_map: FxHashMap<&str, &Expr> =
FxHashMap::with_capacity_and_hasher(args.len() + keywords.len(), FxBuildHasher);
// Process positional arguments.
for (arg_name, value) in arg_spec.iter().zip(args) {
args_map.insert(arg_name, value);
}
// Process keyword arguments.
for arg_name in arg_spec.iter().skip(args.len()) {
if let Some(value) = keywords.iter().find_map(|keyword| {
if keyword
.arg
.as_ref()
.is_some_and(|kwarg_name| &kwarg_name == arg_name)View on GitHub (pinned to 15f3fe6b15)
Solutions
- Correct or remove the unknown keyword so the call matches the assertion method's real signature
- Add `# noqa: PT009` if the extra keyword is intentional and the call should stay untouched
- Exclude the rule/fix for that path in `pyproject.toml` (`lint.per-file-ignores` or `lint.ignore = ["PT009"]`)
Example fix
// before self.assertRaises(ValueError, msgg='bad input') // after self.assertRaises(ValueError, msg='bad input')
Defensive patterns
Strategy: validation
Validate before calling
import inspect, ast
def keywords_in_signature(call: ast.Call) -> bool:
names = {kw.arg for kw in call.keywords if kw.arg is not None}
return bool(names) and all(n in {'msg', 'msg_pattern', 'expected_regex', 'expected_exception', 'places', 'delta', 'seq', 'members', 'container', 'subset', 'superset'} for n in names) Type guard
def has_known_kwargs(node: ast.Call) -> bool:
return all(kw.arg is not None for kw in node.keywords) and keywords_in_signature(node) Prevention
- Only pass keywords documented for the assertion method; verify spelling (e.g. `msg`, not `msgg`)
- Run ruff with `--diff` to see which findings get fixes before applying them
- Suppress PT009 deliberately with noqa when extending assertion APIs in test base classes
When it happens
Trigger: `ruff check --fix` on a call like `self.assertEqual(a, b, custom_flag=True)` (a keyword that is not part of `assertEqual`'s known spec) or a misspelled keyword such as `self.assertRaises(Exception, msgg='x')`.
Common situations: Typos in keyword names, keywords from subclasses or stubs the spec doesn't know, and code written against third-party test frameworks that mirror unittest APIs.
Related errors
- Variable-length arguments are not supported
- Cannot fix `{self}`
- Missing argument `expr`
- Failed to collapse `with`: {err}
- Unable to fix multiline statement
AI-assisted analysis of astral-sh/ruff@15f3fe6b15 (2026-09-05).
Data as JSON: /api/errors/a53c3758f05f3ed6.
Report an issue: GitHub.