{"record":{"id":"27783714a895dcad","repo":"pytest-dev/pytest","slug":"unexpected-character-s-value-token-value","errorCode":null,"errorMessage":"unexpected character/s \"{value_token.value}\"","messagePattern":"unexpected character/s \"(.+?)\"","errorType":"exception","errorClass":"SyntaxError","httpStatus":null,"severity":"error","filePath":"src/_pytest/mark/expression.py","lineNumber":239,"sourceCode":"    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)\n        elif value_token.value in BUILTIN_MATCHERS:\n            value = BUILTIN_MATCHERS[value_token.value]\n        else:\n            raise SyntaxError(\n                f'unexpected character/s \"{value_token.value}\"',\n                (FILE_NAME, 1, value_token.pos + 1, s.input),\n            )\n\n    ret = ast.keyword(keyword_name.value, ast.Constant(value))\n    return ret\n\n\ndef all_kwargs(s: Scanner) -> list[ast.keyword]:\n    ret = [single_kwarg(s)]\n    while s.accept(TokenType.COMMA):\n        ret.append(single_kwarg(s))\n    return ret\n\n\nclass ExpressionMatcher(Protocol):\n    \"\"\"A callable which, given an identifier and optional kwargs, should return\n    whether it matches in an :class:`Expression` evaluation.","sourceCodeStart":221,"sourceCodeEnd":257,"githubUrl":"https://github.com/pytest-dev/pytest/blob/0d6fbdeffa57c796123f62f81f7dd370d9b7ecdc/src/_pytest/mark/expression.py#L221-L257","documentation":"A SyntaxError raised in single_kwarg when the kwarg value is neither a quoted string, a non-negative/positive integer literal, nor one of the builtin matchers (True/False/None). After failing all branches, the raw value token text is reported as unexpected. This is the value-side counterpart of errors 125/126.","triggerScenarios":"Marker expressions like `-m \"foo(x=1.5)\"` (float), `-m \"foo(x=bar)\"` where `bar` is not True/False/None and not a digit, `-m \"foo(x=-)\"`, or `-m \"foo(x=abc123)\"`. Any IDENT value that is not a recognized builtin and not all-digits triggers it.","commonSituations":"Passing floats, hex, negative non-integers, enum-like names, or variables as kwarg values, expecting Python-level evaluation that the grammar does not perform.","solutions":["Use a quoted string for non-numeric values: `foo(x='bar')`.","Use plain integers (optionally negative) for numbers; avoid floats, hex, or scientific notation.","Use True/False/None (unquoted) for booleans and None.","For richer value types, parameterize the test in code instead of via the -m expression."],"exampleFix":"# before\npytest -m \"foo(x=bar)\"\n# after\npytest -m \"foo(x='bar')\"","handlingStrategy":"validation","validationCode":"def is_legal_marker_value(v) -> bool:\n    if isinstance(v, str):\n        return True\n    if isinstance(v, bool) or v is None:\n        return True\n    if isinstance(v, int):\n        return True\n    return False","typeGuard":"def is_supported_marker_value(v) -> bool:\n    return isinstance(v, (str, int, bool)) or v is None","tryCatchPattern":null,"preventionTips":["Use quoted strings for textual kwarg values.","Limit numeric values to integers.","Use True/False/None unquoted for booleans and None."],"tags":["pytest","marker-expression","kwarg","syntax-error","value-literal"],"backgroundTag":null,"analyzedSha":"0d6fbdeffa57c796123f62f81f7dd370d9b7ecdc","analyzedAt":"2026-08-11T20:52:36.969Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}