pytest-dev/pytest · error · SyntaxError
expected {}; got {}
Error message
expected {}; got {} What it means
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.
Source
Thrown at src/_pytest/mark/expression.py:151
def accept(self, type: TokenType, *, reject: Literal[True]) -> Token: ...
@overload
def accept(
self, type: TokenType, *, reject: Literal[False] = False
) -> Token | None: ...
def accept(self, type: TokenType, *, reject: bool = False) -> Token | None:
if self.current.type is type:
token = self.current
if token.type is not TokenType.EOF:
self.current = next(self.tokens)
return token
if reject:
self.reject((type,))
return None
def reject(self, expected: Sequence[TokenType]) -> NoReturn:
raise SyntaxError(
"expected {}; got {}".format(
" OR ".join(type.value for type in expected),
self.current.type.value,
),
(FILE_NAME, 1, self.current.pos + 1, self.input),
)
# True, False and None are legal match expression identifiers,
# but illegal as Python identifiers. To fix this, this prefix
# is added to identifiers in the conversion to Python AST.
IDENT_PREFIX = "$"
def expression(s: Scanner) -> ast.Expression:
if s.accept(TokenType.EOF):
ret: ast.expr = ast.Constant(False)
else:View on GitHub (pinned to 98b357f69e)
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.
Example fix
# before pytest -m 'slow and' # after pytest -m 'slow and integration'
Defensive patterns
Strategy: validation
Validate before calling
from _pytest.mark.expression import Expression
def parses(expr: str) -> bool:
try:
Expression.compile(expr)
except SyntaxError:
return False
return True Prevention
- Balance parentheses.
- Ensure every `and`/`or` has a left and right operand.
When it happens
Trigger: 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'`).
Common situations: Hand-writing marker expressions; partial edits leaving dangling operators; copy-paste that drops the tail of an expression.
Related errors
- {exc_message}: {e.text}: at column {e.offset}: {e.msg}
- closing quote "{quote_char}" is missing
- escaping with "\" not supported in marker expression
- unexpected character "{input[pos]}"
- not a valid python identifier {keyword_name.value}
AI-assisted analysis of pytest-dev/pytest@98b357f69e (2026-08-04).
Data as JSON: /data/errors/e8c7d925122c29b0.json.
Report an issue: GitHub.