{"id":"0fc7ef7b8eea2769","repo":"pytest-dev/pytest","slug":"not-a-valid-python-identifier-keyword-name-value","errorCode":null,"errorMessage":"not a valid python identifier {keyword_name.value}","messagePattern":"not a valid python identifier (.+?)","errorType":"exception","errorClass":"SyntaxError","httpStatus":null,"severity":"error","filePath":"src/_pytest/mark/expression.py","lineNumber":217,"sourceCode":"    if ident:\n        name = ast.Name(IDENT_PREFIX + ident.value, ast.Load())\n        if s.accept(TokenType.LPAREN):\n            ret = ast.Call(func=name, args=[], keywords=all_kwargs(s))\n            s.accept(TokenType.RPAREN, reject=True)\n        else:\n            ret = name\n        return ret\n\n    s.reject((TokenType.NOT, TokenType.LPAREN, TokenType.IDENT))\n\n\nBUILTIN_MATCHERS = {\"True\": True, \"False\": False, \"None\": None}\n\n\ndef single_kwarg(s: Scanner) -> ast.keyword:\n    keyword_name = s.accept(TokenType.IDENT, reject=True)\n    if not keyword_name.value.isidentifier():\n        raise SyntaxError(\n            f\"not a valid python identifier {keyword_name.value}\",\n            (FILE_NAME, 1, keyword_name.pos + 1, s.input),\n        )\n    if keyword.iskeyword(keyword_name.value):\n        raise SyntaxError(\n            f\"unexpected reserved python keyword `{keyword_name.value}`\",\n            (FILE_NAME, 1, keyword_name.pos + 1, s.input),\n        )\n    s.accept(TokenType.EQUAL, reject=True)\n\n    if value_token := s.accept(TokenType.STRING):\n        value: str | int | bool | None = value_token.value[1:-1]  # strip quotes\n    else:\n        value_token = s.accept(TokenType.IDENT, reject=True)\n        if (number := value_token.value).isdigit() or (\n            number.startswith(\"-\") and number[1:].isdigit()\n        ):\n            value = int(number)","sourceCodeStart":199,"sourceCodeEnd":235,"githubUrl":"https://github.com/pytest-dev/pytest/blob/98b357f69e380da908740a212288d73b2ee06687/src/_pytest/mark/expression.py#L199-L235","documentation":"Inside `ident(name=value)` kwargs, the `name` part must be a valid Python identifier. After lexing it as an IDENT token the parser checks `str.isidentifier()`; if it fails (e.g. starts with a digit, contains `-`), this SyntaxError is raised at the name's column.","triggerScenarios":"Writing `foo(1st=...)`, `foo(my-name=...)`, or any kwarg name with non-identifier characters in a `-m` expression.","commonSituations":"Using kebab-case or numeric-prefixed kwarg names; pasting config keys verbatim into marker expressions.","solutions":["Rename the kwarg to a valid Python identifier (letters/digits/underscore, not starting with a digit).","Register the marker with a proper identifier name and map the external key inside your matcher."],"exampleFix":"# before\npytest -m 'env(target-os=linux)'\n# after\npytest -m 'env(target_os=\"linux\")'","handlingStrategy":"validation","validationCode":"def kwarg_name_ok(name: str) -> bool:\n    return name.isidentifier()","typeGuard":"def is_valid_kwarg_name(name: object) -> bool:\n    return isinstance(name, str) and name.isidentifier()","tryCatchPattern":null,"preventionTips":["Use snake_case identifier names for kwargs.","Avoid digits at the start and `-`/special chars in kwarg names."],"tags":["pytest","marker-expression","kwargs","identifier"],"analyzedSha":"98b357f69e380da908740a212288d73b2ee06687","analyzedAt":"2026-08-04T20:26:34.442Z","schemaVersion":2}