python/cpython · error · RuntimeError

Cannot enter %r twice

Error message

Cannot enter %r twice

What it means

Raised by catch_warnings.__enter__ when a single catch_warnings instance is used as a context manager more than once. The object saves the previous filter state/hook on entry and restores it on exit, so re-entering would overwrite the first saved state and corrupt restoration; an _entered flag therefore makes the second entry fail with RuntimeError('Cannot enter %r twice').

Source

Thrown at Lib/_py_warnings.py:700

        self._module = sys.modules['warnings'] if module is None else module
        self._entered = False
        if action is None:
            self._filter = None
        else:
            self._filter = (action, category, lineno, append)

    def __repr__(self):
        args = []
        if self._record:
            args.append("record=True")
        if self._module is not sys.modules['warnings']:
            args.append("module=%r" % self._module)
        name = type(self).__name__
        return "%s(%s)" % (name, ", ".join(args))

    def __enter__(self):
        if self._entered:
            raise RuntimeError("Cannot enter %r twice" % self)
        self._entered = True
        with _wm._lock:
            if _use_context:
                self._saved_context, context = self._module._new_context()
            else:
                context = None
                self._filters = self._module.filters
                self._module.filters = self._filters[:]
                self._showwarnmsg_impl = self._module._showwarnmsg_impl
            self._showwarning = self._module.showwarning
            self._module._filters_mutated_lock_held()
            if self._record:
                if _use_context:
                    context.log = log = []
                else:
                    log = []
                    self._module._showwarnmsg_impl = log.append
                # Reset showwarning() to the default implementation to make sure

View on GitHub (pinned to bc6749cc3b)

Solutions

  1. Create a fresh instance for each use: `with warnings.catch_warnings(record=True) as w:` inline
  2. Make fixtures function-scoped so every test gets a new catch_warnings
  3. If you need the object ahead of time, instantiate it right before the with statement
  4. Never store catch_warnings on long-lived objects (class attributes, module globals)

Example fix

# before
_caught = warnings.catch_warnings(record=True)
with _caught as w:
    ...
with _caught as w:      # RuntimeError: Cannot enter ... twice
    ...

# after
with warnings.catch_warnings(record=True) as w:
    ...
with warnings.catch_warnings(record=True) as w:
    ...
Defensive patterns

Strategy: validation

Validate before calling

import warnings

def fresh_catch(record=True):
    """Always returns a never-entered catch_warnings."""
    return warnings.catch_warnings(record=record)

# use a new one per block:
with fresh_catch() as w:
    ...

Type guard

def is_enterable(cw) -> bool:
    return not getattr(cw, '_entered', False)

Try / catch

try:
    with cw:
        ...
except RuntimeError as e:
    if 'Cannot enter' in str(e):
        with warnings.catch_warnings(record=cw._record) as w:  # start fresh
            ...
    else:
        raise

Prevention

When it happens

Trigger: cw = warnings.catch_warnings(record=True) created once (e.g. on a test class or module) and reused across two `with cw:` blocks; a helper fixture returning a cached catch_warnings; storing the instance on self and entering it in multiple methods.

Common situations: pytest fixtures that instantiate catch_warnings at module scope instead of per-test; refactoring a `with` block into two blocks while keeping the shared object; recursive code paths that each try to enter the same saved context manager.

Related errors


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