pytest-dev/pytest · error · UsageError

invalid lineno

Error message

invalid lineno {lineno_!r}: {e}

What it means

Raised by parse_warning_filter() when the lineno field (5th colon-separated segment) of a warning filter is not a valid non-negative integer. The field is parsed via int() and explicitly checked for negativity. The original ValueError message is included.

Solutions

  1. Set the line field to a non-negative integer or omit it (use empty string)
  2. If you don't need a line filter, leave the field blank: "ignore::DeprecationWarning:mymodule:"
  3. Double-check the field is a plain integer string with no decimal point or sign

Example fix

# pyproject.toml — before
filterwarnings = ["ignore::DeprecationWarning:mymodule:abc"]

# after
filterwarnings = ["ignore::DeprecationWarning:mymodule:42"]
Defensive patterns

Strategy: validation

Validate before calling

def validate_warning_filter_lineno(arg: str) -> bool:
    parts = arg.split(':')
    if len(parts) < 5 or not parts[4].strip():
        return True  # line field absent/empty is valid
    try:
        return int(parts[4].strip()) >= 0
    except ValueError:
        return False

Try / catch

from pytest import UsageError
try:
    parse_warning_filter(arg, escape=True)
except UsageError as e:
    print(f"Invalid lineno in filter: {e}")

Prevention

When it happens

Trigger: Providing a warning filter where the line field is a non-numeric string, a float, or a negative number. Example: filterwarnings = ["ignore::DeprecationWarning:mymodule:abc"] or ["ignore::DeprecationWarning:mymodule:-5"]. The int(lineno_) call raises ValueError or the negativity check fails.

Common situations: Typo in the line number field. Using a float or expression. Copying a filter with an invalid line segment. Forgetting that the line field is 1-indexed and must be non-negative.

Related errors


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

Appendix: source

Thrown at src/_pytest/config/__init__.py:2311

    try:
        category: type[Warning] = _resolve_warning_category(category_)
    except ImportError:
        raise
    except Exception:
        exc_info = ExceptionInfo.from_current()
        exception_text = exc_info.getrepr(style="native")
        raise UsageError(error_template.format(error=exception_text)) from None
    if message and escape:
        message = re.escape(message)
    if module and escape:
        module = re.escape(module) + r"\Z"
    if lineno_:
        try:
            lineno = int(lineno_)
            if lineno < 0:
                raise ValueError("number is negative")
        except ValueError as e:
            raise UsageError(
                error_template.format(error=f"invalid lineno {lineno_!r}: {e}")
            ) from None
    else:
        lineno = 0
    try:
        re.compile(message)
        re.compile(module)
    except re.error as e:
        raise UsageError(
            error_template.format(error=f"Invalid regex {e.pattern!r}: {e}")
        ) from None
    return action, message, category, module, lineno


def _resolve_warning_category(category: str) -> type[Warning]:
    """
    Copied from warnings._getcategory, but changed so it lets exceptions (specially ImportErrors)
    propagate so we can get access to their tracebacks (#9218).

View on GitHub (pinned to 0d6fbdeffa)