RustPython/RustPython · error · RuntimeError
Cannot exit %r without entering first
Error message
Cannot exit %r without entering first
What it means
warnings.catch_warnings.__exit__ raises RuntimeError when the instance was never entered, because there is no saved filters/showwarning state to restore. It fires when __exit__ is invoked manually or out of order -- i.e. the with-protocol pairing of __enter__/__exit__ was broken by hand-rolled code.
Source
Thrown at Lib/_py_warnings.py:670
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
# that _showwarnmsg() calls _showwarnmsg_impl()
self._module.showwarning = self._module._showwarning_orig
else:
log = None
if self._filter is not None:
self._module.simplefilter(*self._filter)
return log
def __exit__(self, *exc_info):
if not self._entered:
raise RuntimeError("Cannot exit %r without entering first" % self)
with _wm._lock:
if _use_context:
self._module._warnings_context.set(self._saved_context)
else:
self._module.filters = self._filters
self._module.showwarning = self._showwarning
self._module._showwarnmsg_impl = self._showwarnmsg_impl
self._module._filters_mutated_lock_held()
class deprecated:
"""Indicate that a class, function or overload is deprecated.
When this decorator is applied to an object, the type checker
will generate a diagnostic on usage of the deprecated object.
Usage:
View on GitHub (pinned to aaeab4f754)
Solutions
- Use the with statement instead of calling __enter__/__exit__ manually
- If manual pairing is unavoidable, set a flag and only call __exit__ after a successful __enter__
- Audit custom wrappers so exit runs exactly once per enter, including on exceptions
Example fix
# before
cm = warnings.catch_warnings()
cm.__exit__(None, None, None) # RuntimeError: Cannot exit ... without entering first
# after
with warnings.catch_warnings():
... Defensive patterns
Strategy: validation
Validate before calling
if getattr(cm, "_entered", False):
cm.__exit__(None, None, None) # only exit what was actually entered Type guard
def is_entered(cm) -> bool:
return bool(getattr(cm, "_entered", False)) Try / catch
try:
cm.__exit__(None, None, None)
except RuntimeError as e:
if "without entering first" in str(e):
pass # nothing was saved; nothing to restore
else:
raise Prevention
- Prefer the with statement over manual __enter__/__exit__ pairing
- Guard cleanup paths so exit runs exactly once per successful enter
- In fixtures, pair enter/exit symmetrically in setup/teardown and skip teardown if setup failed
When it happens
Trigger: Calling cm.__exit__(None, None, None) without a prior cm.__enter__(); framework or fixture code that pairs enter/exit incorrectly; cleanup paths that call exit a second time unguarded.
Common situations: Custom context-manager wrappers or test fixtures that drive __enter__/__exit__ by hand; try/finally blocks imitating the with statement; double-cleanup on exception paths.
Related errors
- Cannot enter %r twice
- Unrecognized action (%r) in warnings.filters: %s
- {name!r} was slated for removal after Python {remove_formatt
- BUILD_GNU_TYPE is not defined
- Expected Theme object, found {t}
AI-assisted analysis of RustPython/RustPython@aaeab4f754 (2026-08-17).
Data as JSON: /api/errors/e559d79f61d38571.
Report an issue: GitHub.