{"record":{"id":"e8c7d925122c29b0","repo":"pytest-dev/pytest","slug":"expected-got","errorCode":null,"errorMessage":"expected {}; got {}","messagePattern":"expected (.+?); got (.+?)","errorType":"exception","errorClass":"SyntaxError","httpStatus":null,"severity":"error","filePath":"src/_pytest/mark/expression.py","lineNumber":151,"sourceCode":"    def accept(self, type: TokenType, *, reject: Literal[True]) -> Token: ...\n\n    @overload\n    def accept(\n        self, type: TokenType, *, reject: Literal[False] = False\n    ) -> Token | None: ...\n\n    def accept(self, type: TokenType, *, reject: bool = False) -> Token | None:\n        if self.current.type is type:\n            token = self.current\n            if token.type is not TokenType.EOF:\n                self.current = next(self.tokens)\n            return token\n        if reject:\n            self.reject((type,))\n        return None\n\n    def reject(self, expected: Sequence[TokenType]) -> NoReturn:\n        raise SyntaxError(\n            \"expected {}; got {}\".format(\n                \" OR \".join(type.value for type in expected),\n                self.current.type.value,\n            ),\n            (FILE_NAME, 1, self.current.pos + 1, self.input),\n        )\n\n\n# True, False and None are legal match expression identifiers,\n# but illegal as Python identifiers. To fix this, this prefix\n# is added to identifiers in the conversion to Python AST.\nIDENT_PREFIX = \"$\"\n\n\ndef expression(s: Scanner) -> ast.Expression:\n    if s.accept(TokenType.EOF):\n        ret: ast.expr = ast.Constant(False)\n    else:","sourceCodeStart":133,"sourceCodeEnd":169,"githubUrl":"https://github.com/pytest-dev/pytest/blob/0d6fbdeffa57c796123f62f81f7dd370d9b7ecdc/src/_pytest/mark/expression.py#L133-L169","documentation":"A SyntaxError raised by Scanner.reject when the parser expected one token type (or a set of alternatives) but the current token did not match. The message lists the expected token names joined by ' OR ' and the actually-seen token. It is the grammar-level parse error complementing the lexer-level errors 121-123.","triggerScenarios":"Malformed grammar such as `-m 'not'` (NOT followed by EOF, expected IDENT/LPAREN), `-m 'a and'` (AND with no right operand), `-m '(a'` (LPAREN never closed, expected RPAREN), or `-m 'foo('` (LPAREN not followed by IDENT for kwargs).","commonSituations":"Incomplete boolean expressions, dangling operators, unbalanced parentheses, or starting a kwarg list but omitting the identifier.","solutions":["Read the 'expected X OR Y; got Z' message to see which token is missing.","Complete the expression: add the missing operand, close parenthesis, or remove the trailing operator.","For complex expressions, build them incrementally and re-run to get the next parse hint."],"exampleFix":"# before\npytest -m 'not'\n# after\npytest -m 'not slow'","handlingStrategy":"validation","validationCode":"from _pytest.mark.expression import Expression\ndef parse_or_report(expr: str):\n    try:\n        Expression.compile(expr)\n    except SyntaxError as e:\n        return {'ok': False, 'msg': e.msg, 'offset': e.offset}\n    return {'ok': True}","typeGuard":null,"tryCatchPattern":"try:\n    deselect_by_mark(items, config)\nexcept SyntaxError as e:\n    # 'expected X OR Y; got Z' -> tell user what token is missing\n    ...","preventionTips":["Build boolean expressions from a template, not free text.","Balance parentheses explicitly when constructing expressions.","Test marker expressions in isolation before running the suite."],"tags":["pytest","marker-expression","parser","syntax-error","grammar"],"backgroundTag":null,"analyzedSha":"0d6fbdeffa57c796123f62f81f7dd370d9b7ecdc","analyzedAt":"2026-08-11T20:52:36.969Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}