pytest-dev/pytest · error · SyntaxError
not a valid python identifier
Error message
not a valid python identifier {keyword_name.value} What it means
A SyntaxError raised in single_kwarg when the kwarg name token (parsed as an IDENT) is not a valid Python identifier according to str.isidentifier(). Because the tokenizer accepts a broad character class, an identifier-like token such as `1foo`, `a-b`, or `a.b` can reach this check and be rejected. The column reported is the 1-based position of the offending name.
Solutions
- Rename the kwarg to a valid Python identifier: letters, digits, underscores, not starting with a digit.
- Check that you did not accidentally include a hyphen or dot from a CLI flag.
- Define the marker's kwargs with proper identifier names in conftest or plugin code.
Example fix
# before pytest -m "foo(1x='y')" # after pytest -m "foo(x='y')"
Defensive patterns
Strategy: type-guard
Validate before calling
def valid_kwarg_name(name: str) -> bool:
return name.isidentifier() and not name[0].isdigit() Type guard
def is_valid_marker_kwarg_name(name: str) -> bool:
return isinstance(name, str) and name.isidentifier() Prevention
- Use Python-identifier rules for marker kwarg names.
- Avoid dots, dashes, and leading digits in kwarg names.
- Generate kwarg names from an allow-list.
When it happens
Trigger: Marker expressions like `-m "foo(1x='y')"`, `-m "foo(a-b='y')"`, or `-m "foo(a.b='y')"` where the kwarg name fails Python identifier rules. Also triggered by tokens that the lexer grouped but which are not legal parameter names.
Common situations: Using numeric or symbol-laden kwarg names in marker filters, mistyping a kwarg name, or assuming Python attribute syntax (dashes, dots) works in marker expressions.
Related errors
- unexpected character/s
- unexpected reserved python keyword
- closing quote " " is missing
- escaping with "\" not supported in marker expression
- : : at column
AI-assisted analysis of pytest-dev/pytest@0d6fbdeffa (2026-08-11).
Data as JSON: /api/errors/0fc7ef7b8eea2769.
Report an issue: GitHub.
Appendix: source
Thrown at src/_pytest/mark/expression.py:217
if ident:
name = ast.Name(IDENT_PREFIX + ident.value, ast.Load())
if s.accept(TokenType.LPAREN):
ret = ast.Call(func=name, args=[], keywords=all_kwargs(s))
s.accept(TokenType.RPAREN, reject=True)
else:
ret = name
return ret
s.reject((TokenType.NOT, TokenType.LPAREN, TokenType.IDENT))
BUILTIN_MATCHERS = {"True": True, "False": False, "None": None}
def single_kwarg(s: Scanner) -> ast.keyword:
keyword_name = s.accept(TokenType.IDENT, reject=True)
if not keyword_name.value.isidentifier():
raise SyntaxError(
f"not a valid python identifier {keyword_name.value}",
(FILE_NAME, 1, keyword_name.pos + 1, s.input),
)
if keyword.iskeyword(keyword_name.value):
raise SyntaxError(
f"unexpected reserved python keyword `{keyword_name.value}`",
(FILE_NAME, 1, keyword_name.pos + 1, s.input),
)
s.accept(TokenType.EQUAL, reject=True)
if value_token := s.accept(TokenType.STRING):
value: str | int | bool | None = value_token.value[1:-1] # strip quotes
else:
value_token = s.accept(TokenType.IDENT, reject=True)
if (number := value_token.value).isdigit() or (
number.startswith("-") and number[1:].isdigit()
):
value = int(number)View on GitHub (pinned to 0d6fbdeffa)