pytest-dev/pytest · error · UsageError

: : at column

Error message

{exc_message}: {e.text}: at column {e.offset}: {e.msg}

What it means

Raised as a UsageError when pytest fails to compile a marker or keyword expression supplied via -m / -k (or the API equivalent). The original SyntaxError from the expression parser is unwrapped and re-thrown with a pytest-level message, prefixing the location-specific details (offending text, column offset, message). It stops collection because pytest cannot decide which tests to select.

Solutions

  1. Re-run pytest and read the full message: it names the offending text, the 1-based column, and the parser's complaint.
  2. Balance parentheses/quotes in the -m or -k value and quote the whole expression in the shell.
  3. If the expression is built dynamically, validate it with `Expression.compile(expr)` in a try/except before passing it to pytest.
  4. Simplify the expression to a single marker name and re-add operators one at a time to isolate the syntax fault.

Example fix

# before
pytest -m 'not (smoke'
# after
pytest -m 'not smoke'
Defensive patterns

Strategy: validation

Validate before calling

from _pytest.mark.expression import Expression

def safe_marker_expr(expr: str) -> bool:
    try:
        Expression.compile(expr)
        return True
    except SyntaxError:
        return False

Try / catch

from _pytest.config import UsageError
try:
    deselect_by_keyword(items, config)
except UsageError as e:
    # report the bad expression to the user / fall back to no filter
    print(f'invalid selection expression: {e}')

Prevention

When it happens

Trigger: Calling pytest with `-m 'not (smoke'` (unbalanced parens), `-k 'test_ and'` (trailing operator), or programmatically invoking deselect_by_mark / deselect_by_keyword with a malformed expression string. Any string that Expression.compile cannot parse triggers it.

Common situations: Typos in CLI selection expressions, copy-pasting a partial expression, using shell quoting that strips parentheses, or upgrading pytest where the marker expression grammar changed (e.g. introducing kwargs).

Related errors


AI-assisted analysis of pytest-dev/pytest@0d6fbdeffa (2026-08-11). Data as JSON: /api/errors/871351ccf4f92d5d. Report an issue: GitHub.

Appendix: source

Thrown at src/_pytest/mark/__init__.py:283

    expr = _parse_expression(matchexpr, "Wrong expression passed to '-m'")
    remaining: list[Item] = []
    deselected: list[Item] = []
    for item in items:
        if expr.evaluate(MarkMatcher.from_markers(item.iter_markers())):
            remaining.append(item)
        else:
            deselected.append(item)
    if deselected:
        config.hook.pytest_deselected(items=deselected)
        items[:] = remaining


def _parse_expression(expr: str, exc_message: str) -> Expression:
    try:
        return Expression.compile(expr)
    except SyntaxError as e:
        raise UsageError(
            f"{exc_message}: {e.text}: at column {e.offset}: {e.msg}"
        ) from None


def pytest_collection_modifyitems(items: list[Item], config: Config) -> None:
    deselect_by_keyword(items, config)
    deselect_by_mark(items, config)


def pytest_configure(config: Config) -> None:
    config.stash[old_mark_config_key] = MARK_GEN._config
    MARK_GEN._config = config

    # Eagerly validate the value; it is only read lazily during collection.
    config.getini(EMPTY_PARAMETERSET_OPTION)


def pytest_unconfigure(config: Config) -> None:

View on GitHub (pinned to 0d6fbdeffa)