{"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/98b357f69e380da908740a212288d73b2ee06687/src/_pytest/mark/expression.py#L133-L169","documentation":"Generic parser error from `Scanner.reject`: the parser expected one of a set of token types (e.g. identifier, parenthesis, EOF) but the current token was something else. The message lists what was expected (joined by ` OR `) and what was actually seen.","triggerScenarios":"Trailing operator with no operand (`-m 'foo and'`), missing closing paren (`-m '(foo'`), empty parens (`-m 'foo()'` with kwargs expected), or duplicated operators (`-m 'foo and and bar'`).","commonSituations":"Hand-writing marker expressions; partial edits leaving dangling operators; copy-paste that drops the tail of an expression.","solutions":["Match the expected vs got token types in the message to locate the missing/extra token.","Balance every `(` with a `)` and ensure each `and`/`or` has operands on both sides.","Simplify the expression to the smallest failing form to isolate the syntax issue."],"exampleFix":"# before\npytest -m 'slow and'\n# after\npytest -m 'slow and integration'","handlingStrategy":"validation","validationCode":"from _pytest.mark.expression import Expression\ndef parses(expr: str) -> bool:\n    try:\n        Expression.compile(expr)\n    except SyntaxError:\n        return False\n    return True","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Balance parentheses.","Ensure every `and`/`or` has a left and right operand."],"tags":["pytest","marker-expression","parser","syntax"],"analyzedSha":"98b357f69e380da908740a212288d73b2ee06687","analyzedAt":"2026-08-04T20:26:34.442Z","schemaVersion":2}