Skip to content

Raise From

raise NewException(...) from original_exception (Python 3.3+) explicitly links a new exception to the one that caused it. Python also does this implicitly β€” any exception raised while handling another exception gets chained automatically β€” but raise ... from ... lets you control and clarify that link, including suppressing it entirely.

Without chaining, converting a low-level exception into a higher-level, more meaningful one throws away the original cause:

def load_config(path):
try:
with open(path) as f:
return f.read()
except FileNotFoundError:
raise ValueError(f"Config not found: {path}")
# Traceback shows only ValueError β€” the original FileNotFoundError and
# its details (which file, which line) are gone from the visible chain
# unless you're on 3.3+, where it's captured automatically anyway.
def load_config(path):
try:
with open(path) as f:
return f.read()
except FileNotFoundError as e:
raise ValueError(f"Config not found: {path}") from e
# Traceback now shows both:
# FileNotFoundError: [Errno 2] No such file or directory: 'config.yml'
#
# The above exception was the direct cause of the following exception:
#
# ValueError: Config not found: config.yml
# Suppressing the chain entirely when the original truly isn't useful context
try:
risky_operation()
except SomeError:
raise CleanError("Something went wrong") from None
# Traceback shows only CleanError β€” no "During handling of..." noise
  • Full debugging context: the traceback shows both exceptions β€” what ultimately went wrong and what originally triggered it β€” instead of losing the root cause.
  • Explicit intent: from e says β€œthis new exception is because of e” (sets __cause__); from None says β€œdeliberately don’t show a cause,” both clearer than accidental chaining.
  • Distinguishes deliberate vs. accidental: a bug that raises a second, unrelated exception while handling the first still shows up in the traceback (__context__) even without from, which is often exactly what you want when debugging β€” you see that something also broke in your except block.
  • raise X from Y sets X.__cause__ = Y and prints β€œThe above exception was the direct cause of the following exception.”
  • Without from, an exception raised inside an except block still gets chained automatically via __context__, printed as β€œDuring handling of the above exception, another exception occurred.”
  • raise X from None explicitly suppresses the chain display (sets __suppress_context__ = True) β€” useful when the original exception is an implementation detail that would just confuse the caller.
  • __cause__ (explicit, via from) and __context__ (implicit, automatic) are different attributes β€” from always takes precedence for what’s displayed.
  1. What does raise ValueError("bad config") from e set on the new exception?

    Answer`__cause__` is set to `e`, and the traceback shows `e` as "the direct cause of" the new `ValueError`.
  2. If you raise a new exception inside an except block without using from, is the original exception lost?

    AnswerNo β€” it's still shown, via the implicit `__context__` chain ("During handling of the above exception, another exception occurred"), just without the explicit "direct cause" framing.
  3. How do you suppress the chained-exception traceback entirely?

    Answer`raise NewException(...) from None`.