python/cpython · error · ValueError

invalid action: {action!r}

Error message

invalid action: {action!r}

What it means

Raised by warnings.filterwarnings when the action string is not one of the recognized filter actions: 'error', 'ignore', 'always', 'all', 'default', 'module', 'once'. The function validates its arguments up front because filter entries are consumed later by the matching engine, which cannot interpret unknown actions. 'all' is an alias of 'always'; there is no 'warn', 'hide', or 'once/module' style shorthand.

Source

Thrown at Lib/_py_warnings.py:267

            return fw(msg.message, msg.category,
                      msg.filename, msg.lineno, msg.line)
    return _wm._formatwarnmsg_impl(msg)


def filterwarnings(action, message="", category=Warning, module="", lineno=0,
                   append=False):
    """Insert an entry into the list of warnings filters (at the front).

    'action' -- one of "error", "ignore", "always", "all", "default", "module",
                or "once"
    'message' -- a regex that the warning message must match
    'category' -- a class that the warning must be a subclass of
    'module' -- a regex that the module name must match
    'lineno' -- an integer line number, 0 matches all warnings
    'append' -- if true, append to the list of filters
    """
    if action not in {"error", "ignore", "always", "all", "default", "module", "once"}:
        raise ValueError(f"invalid action: {action!r}")
    if not isinstance(message, str):
        raise TypeError("message must be a string")
    if not isinstance(category, type) or not issubclass(category, Warning):
        raise TypeError("category must be a Warning subclass")
    if not isinstance(module, str):
        raise TypeError("module must be a string")
    if not isinstance(lineno, int):
        raise TypeError("lineno must be an int")
    if lineno < 0:
        raise ValueError("lineno must be an int >= 0")

    if message or module:
        import re

    if message:
        message = re.compile(message, re.I)
    else:
        message = None

View on GitHub (pinned to bc6749cc3b)

Solutions

  1. Use one of the seven valid actions: error, ignore, always, all, default, module, once
  2. Strip/normalize user- or config-supplied actions: action.strip().lower() before calling
  3. Validate actions against the set when parsing config files, and reject early with a clear message

Example fix

# before
warnings.filterwarnings('ignore-once', category=DeprecationWarning)  # ValueError

# after
warnings.filterwarnings('once', category=DeprecationWarning)
Defensive patterns

Strategy: validation

Validate before calling

VALID_ACTIONS = {'error', 'ignore', 'always', 'all', 'default', 'module', 'once'}

def safe_filterwarnings(action, *args, **kwargs):
    action = str(action).strip().lower()
    if action not in VALID_ACTIONS:
        raise ValueError(f'{action!r} is not a valid action; choose from {sorted(VALID_ACTIONS)}')
    import warnings
    return warnings.filterwarnings(action, *args, **kwargs)

Type guard

def is_valid_action(action) -> bool:
    return isinstance(action, str) and action.strip().lower() in {
        'error', 'ignore', 'always', 'all', 'default', 'module', 'once'}

Prevention

When it happens

Trigger: warnings.filterwarnings(action='suppress'/'hide'/'warn'/'ignore-once') — any misspelled or invented action string; also actions read from a config file and forwarded verbatim; actions with trailing whitespace or different casing ('Ignore') since the check is case-sensitive.

Common situations: Typo'd action names in test-suite bootstrap (pytest.ini-style warning config translated manually); actions loaded from YAML/JSON settings; snippets written for other warning systems (e.g. Ruby's $VERBOSE vocabulary); uppercase or padded values from user input.

Related errors


AI-assisted analysis of python/cpython@bc6749cc3b (2026-08-14). Data as JSON: /api/errors/12b9dc7b228de1ac. Report an issue: GitHub.