The difference is that when you use from, the __cause__ attribute is set and the message states that the exception was directly caused by. If you omit the from then no __cause__ is set, but the __context__ attribute may be set as well, and the traceback then shows the context as during handling something else happened.

Setting the __context__ happens if you used raise in an exception handler; if you used raise anywhere else no __context__ is set either.

If a __cause__ is set, a __suppress_context__ = True flag is also set on the exception; when __suppress_context__ is set to True, the __context__ is ignored when printing a traceback.

When raising from a exception handler where you don't want to show the context (don't want a during handling another exception happened message), then use raise ... from None to set __suppress_context__ to True.

In other words, Python sets a context on exceptions so you can introspect where an exception was raised, letting you see if another exception was replaced by it. You can also add a cause to an exception, making the traceback explicit about the other exception (use different wording), and the context is ignored (but can still be introspected when debugging). Using raise ... from None lets you suppress the context being printed.

See the raise statement documenation:

The from clause is used for exception chaining: if given, the second expression must be another exception class or instance, which will then be attached to the raised exception as the __cause__ attribute (which is writable). If the raised exception is not handled, both exceptions will be printed:

>>> try:
...     print(1 / 0)
... except Exception as exc:
...     raise RuntimeError("Something bad happened") from exc
...
Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
ZeroDivisionError: int division or modulo by zero

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "<stdin>", line 4, in <module>
RuntimeError: Something bad happened

A similar mechanism works implicitly if an exception is raised inside an exception handler or a finally clause: the previous exception is then attached as the new exception’s __context__ attribute:

>>> try:
...     print(1 / 0)
... except:
...     raise RuntimeError("Something bad happened")
...
Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
ZeroDivisionError: int division or modulo by zero

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "<stdin>", line 4, in <module>
RuntimeError: Something bad happened

Also see the Built-in Exceptions documentation for details on the context and cause information attached to exceptions.

Answer from Martijn Pieters on Stack Overflow
🌐
Bugsink
bugsink.com › blog › using-raise-from-none-in-python
When to use “raise from None” in Python
December 27, 2024 - How: Simply use raise Exception("message") from None to raise an exception without chaining it to the previous one. By default, Python automatically chains exceptions when one is raised during the handling of another.
Top answer
1 of 4
559

The difference is that when you use from, the __cause__ attribute is set and the message states that the exception was directly caused by. If you omit the from then no __cause__ is set, but the __context__ attribute may be set as well, and the traceback then shows the context as during handling something else happened.

Setting the __context__ happens if you used raise in an exception handler; if you used raise anywhere else no __context__ is set either.

If a __cause__ is set, a __suppress_context__ = True flag is also set on the exception; when __suppress_context__ is set to True, the __context__ is ignored when printing a traceback.

When raising from a exception handler where you don't want to show the context (don't want a during handling another exception happened message), then use raise ... from None to set __suppress_context__ to True.

In other words, Python sets a context on exceptions so you can introspect where an exception was raised, letting you see if another exception was replaced by it. You can also add a cause to an exception, making the traceback explicit about the other exception (use different wording), and the context is ignored (but can still be introspected when debugging). Using raise ... from None lets you suppress the context being printed.

See the raise statement documenation:

The from clause is used for exception chaining: if given, the second expression must be another exception class or instance, which will then be attached to the raised exception as the __cause__ attribute (which is writable). If the raised exception is not handled, both exceptions will be printed:

>>> try:
...     print(1 / 0)
... except Exception as exc:
...     raise RuntimeError("Something bad happened") from exc
...
Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
ZeroDivisionError: int division or modulo by zero

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "<stdin>", line 4, in <module>
RuntimeError: Something bad happened

A similar mechanism works implicitly if an exception is raised inside an exception handler or a finally clause: the previous exception is then attached as the new exception’s __context__ attribute:

>>> try:
...     print(1 / 0)
... except:
...     raise RuntimeError("Something bad happened")
...
Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
ZeroDivisionError: int division or modulo by zero

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "<stdin>", line 4, in <module>
RuntimeError: Something bad happened

Also see the Built-in Exceptions documentation for details on the context and cause information attached to exceptions.

2 of 4
26

In 2005, PEP 3134, Exception Chaining and Embedded Tracebacks introduced exception chaining:

  • implicit chaining with explicit raise EXCEPTION or implicit raise (__context__ attribute);
  • explicit chaining with explicit raise EXCEPTION from CAUSE (__cause__ attribute).

Motivation

During the handling of one exception (exception A), it is possible that another exception (exception B) may occur. In today’s Python (version 2.4), if this happens, exception B is propagated outward and exception A is lost. In order to debug the problem, it is useful to know about both exceptions. The __context__ attribute retains this information automatically.

Sometimes it can be useful for an exception handler to intentionally re-raise an exception, either to provide extra information or to translate an exception to another type. The __cause__ attribute provides an explicit way to record the direct cause of an exception.

[…]

Implicit Exception Chaining

Here is an example to illustrate the __context__ attribute:

def compute(a, b):
    try:
        a/b
    except Exception, exc:
        log(exc)

def log(exc):
    file = open('logfile.txt')  # oops, forgot the 'w'
    print >>file, exc
    file.close()

Calling compute(0, 0) causes a ZeroDivisionError. The compute() function catches this exception and calls log(exc), but the log() function also raises an exception when it tries to write to a file that wasn’t opened for writing.

In today’s Python, the caller of compute() gets thrown an IOError. The ZeroDivisionError is lost. With the proposed change, the instance of IOError has an additional __context__ attribute that retains the ZeroDivisionError.

[…]

Explicit Exception Chaining

The __cause__ attribute on exception objects is always initialized to None. It is set by a new form of the raise statement:

raise EXCEPTION from CAUSE

which is equivalent to:

exc = EXCEPTION
exc.__cause__ = CAUSE
raise exc

In the following example, a database provides implementations for a few different kinds of storage, with file storage as one kind. The database designer wants errors to propagate as DatabaseError objects so that the client doesn’t have to be aware of the storage-specific details, but doesn’t want to lose the underlying error information.

class DatabaseError(Exception):
    pass

class FileDatabase(Database):
    def __init__(self, filename):
        try:
            self.file = open(filename)
        except IOError, exc:
            raise DatabaseError('failed to open') from exc

If the call to open() raises an exception, the problem will be reported as a DatabaseError, with a __cause__ attribute that reveals the IOError as the original cause.

Enhanced Reporting

The default exception handler will be modified to report chained exceptions. The chain of exceptions is traversed by following the __cause__ and __context__ attributes, with __cause__ taking priority. In keeping with the chronological order of tracebacks, the most recently raised exception is displayed last; that is, the display begins with the description of the innermost exception and backs up the chain to the outermost exception. The tracebacks are formatted as usual, with one of the lines:

The above exception was the direct cause of the following exception:

or

During handling of the above exception, another exception occurred:

between tracebacks, depending whether they are linked by __cause__ or __context__ respectively. Here is a sketch of the procedure:

def print_chain(exc):
    if exc.__cause__:
        print_chain(exc.__cause__)
        print '\nThe above exception was the direct cause...'
    elif exc.__context__:
        print_chain(exc.__context__)
        print '\nDuring handling of the above exception, ...'
    print_exc(exc)

[…]

In 2012, PEP 415, Implement Context Suppression with Exception Attributes introduced exception context suppression with explicit raise EXCEPTION from None (__suppress_context__ attribute).

Proposal

A new attribute on BaseException, __suppress_context__, will be introduced. Whenever __cause__ is set, __suppress_context__ will be set to True. In particular, raise exc from cause syntax will set exc.__suppress_context__ to True. Exception printing code will check for that attribute to determine whether context and cause will be printed. __cause__ will return to its original purpose and values.

There is precedence for __suppress_context__ with the print_line_and_file exception attribute.

To summarize, raise exc from cause will be equivalent to:

exc.__cause__ = cause
raise exc

where exc.__cause__ = cause implicitly sets exc.__suppress_context__.

So in PEP 415, the sketch of the procedure given in PEP 3134 for the default exception handler (its job is to report exceptions) becomes the following:

def print_chain(exc):
    if exc.__cause__:
        print_chain(exc.__cause__)
        print '\nThe above exception was the direct cause...'
    elif exc.__context__ and not exc.__suppress_context__:
        print_chain(exc.__context__)
        print '\nDuring handling of the above exception, ...'
    print_exc(exc)
People also ask

When should I use raise X from None in Python?
Use raise X from None when the original exception's detail would distract or confuse the caller. Common cases: translating a generic OSError into a clean ValidationError where the OSError chain adds noise; hiding implementation details in a library public API; surfacing a user-friendly error in a CLI tool where stack traces from internal subsystems aren't useful. The from None part sets __suppress_context__ to True so the traceback shows only your new exception. The original is still accessible via __context__ for debugging, just not printed by default. Use sparingly: hiding context can make d
🌐
codegym.cc
codegym.cc › java blog › learning python › raise, raise from, and re-raising exceptions in python
raise, raise from, and Re-Raising Exceptions in Python | CodeGym
How do I re-raise the current exception in Python?
Use bare raise inside an except block. It re-raises the currently-handled exception, preserving the original traceback so debuggers and logs show where the error truly originated. Pattern: try: do_thing() except SomeError: log_and_handle(); raise. Don't use raise SomeError() to 're-raise' the same type; that creates a new exception object and may lose context. Bare raise is the canonical re-raise; it works only inside an except block (using it elsewhere raises RuntimeError because there's no current exception to re-raise).
🌐
codegym.cc
codegym.cc › java blog › learning python › raise, raise from, and re-raising exceptions in python
raise, raise from, and Re-Raising Exceptions in Python | CodeGym
What is the difference between raise X from Y and just raise X in Python?
raise X from Y sets the new exception's __cause__ attribute to Y, producing 'The above exception was the direct cause of the following exception:' in tracebacks. Plain raise X (inside an except block) sets __context__ implicitly to the currently-handled exception, producing 'During handling of the above exception, another exception occurred:'. The practical difference: __cause__ signals 'I deliberately translated this error into a higher-level one', while __context__ shows 'a second error happened while we were dealing with the first'. Use raise X from Y when wrapping a low-level error into a
🌐
codegym.cc
codegym.cc › java blog › learning python › raise, raise from, and re-raising exceptions in python
raise, raise from, and Re-Raising Exceptions in Python | CodeGym
🌐
Python.org
discuss.python.org › ideas
`raise None` should be a no-op - Ideas - Discussions on Python.org
May 3, 2022 - This is an example from PEP 654: try: low_level_os_operation() except* OSError as errors: exc = errors.subgroup(lambda e: e.errno != errno.EPIPE) if exc is not None: raise exc from None I find that conditional raise at the end quite smelly. Since subgroup can return None (instead of an empty ...
🌐
Reddit
reddit.com › r/learnpython › to raise exceptions, or to return none. best practices?
r/learnpython on Reddit: To raise exceptions, or to return None. Best practices?
October 2, 2024 -

Hi there,

I’ve recently been trying to write type safe code by enforcing strict mypy checking.

In doing so, I’ve realised some holes in my general code style and want to make it A) consistent throughout the code base and B) do it the most pythonic way.

I’m using this with c extension APIs so I’m just going to make up some very contrived examples

Let’s say we have a function which fetches an instance of an object

def get_item(name: str) -> ItemClass:
    if item := api.get_item({‘name’: name}):
        return item

I have to try retrieve the object- at this point I may have the object or I may have “None” or “False” depending on the call.

Using mypy, it requires a return call at the end of the function (a good thing imo). So naturally I add “return None”

But now of course I have to change my function signature.

def get_item(name: str) -> Optional[ItemClass]:
    if item := api.get_item({‘name’: name}):
        return item
    return None

This works, and it still boils down to me having to check the truthyness of the returned value from my function, but I’m wondering if the more pythonic thing to do would be to raise an exception instead of returning None.

What is the communities feeling of best practice? And especially how it ties into writing code that is robust

Many thanks for your time

🌐
Reddit
reddit.com › r/programming › when to use “raise from none” in python
r/programming on Reddit: When to use “raise from None” in Python
December 27, 2024 - Raise from None when you are making some kind of data structure or other total abstraction and want to hide the inner workings away.
🌐
Python
docs.python.org › 2.0 › ref › raise.html
6.8 The raise statement
Otherwise, raise evaluates its first expression, which must yield a string, class, or instance object. If there is a second expression, this is evaluated, else None is substituted. If the first expression is a class object, then the second expression may be an instance of that class or one ...
Find elsewhere
🌐
Python Tutorial
pythontutorial.net › home › python oop › python raise from
Python raise from - Python Tutorial
March 28, 2025 - def divide(a, b): try: return a / b except ZeroDivisionError: raise ValueError('b must not be zero') from None divide(10, 0)Code language: Python (python)
🌐
CodeGym
codegym.cc › java blog › learning python › raise, raise from, and re-raising exceptions in python
raise, raise from, and Re-Raising Exceptions in Python | CodeGym
June 25, 2026 - Four Python raise patterns explained: bare raise to re-raise the current exception, raise X to start fresh, raise X from Y to chain causes explicitly, and raise X from None to suppress the original context.
🌐
Reddit
reddit.com › r/learnpython › is it more pythonic to raise an exception or return none and leave it for the caller to check
r/learnpython on Reddit: Is it more pythonic to raise an exception or return None and leave it for the caller to check
June 24, 2018 -

Though this is probably more of a CS question than a Python specific question, I'm more familiar with py in general. So let's say I have a function that makes an external API call, and returns a list from a parsed JSON response object. Would it be better to raise parameter problems like a malformed url or a status code error ONLY in that function, returning an empty list (or None) to that it evaluates to 'false' but doesn't throw if a call to a sequence is made to the response... <inhales> or raise a value error if nothing is found, leaving the handling up to the caller?

🌐
Astral
docs.astral.sh › ruff › rules › raise-without-from-inside-except
raise-without-from-inside-except (B904) | Ruff - Astral Docs
Without it, Python will implicitly chain from the current exception (setting __context__), but the __cause__ attribute won't be set, which may make debugging slightly more difficult. try: ... except FileNotFoundError: if ...: raise RuntimeError("...") else: raise UserWarning("...") ... try: ... except FileNotFoundError as exc: if ...: raise RuntimeError("...") from None else: raise UserWarning("...") from exc
🌐
Python
docs.python.org › 3 › builtins › exceptions.html
Built-in Exceptions — Python 3.14.7 documentation
This implicit exception context can be supplemented with an explicit cause by using from with raise: ... The expression following from must be an exception or None. It will be set as __cause__ on the raised exception.
🌐
Real Python
realpython.com › python-raise-exception
Python's raise: Effectively Raising Exceptions in Your Code – Real Python
October 20, 2025 - You can also use this syntax to ... when raising your own exception. To illustrate how from None works, say that you’re coding a package to consume an external REST API. You’ve decided to use the requests library to access the API. However, you don’t want to expose the exceptions that this library provides. Instead, you want to use a custom exception. Note: For the code below to work, you must first install the requests library in your current Python environment ...
🌐
InformIT
informit.com › articles › article.aspx
Item 32: Prefer Raising Exceptions to Returning None | Functions | InformIT
You can specify that a function’s return value will always be a float and thus will never be None. However, Python’s gradual typing purposely doesn’t provide a way to indicate when exceptions are part of a function’s interface (also known as checked exceptions). Instead, you have to document the exception-raising behavior and expect callers to rely on that in order to know which exceptions they should plan to catch (see Item 118: “Write Docstrings for Every Function, Class, and Module”).
🌐
Python
peps.python.org › pep-0409
PEP 409 – Suppressing exception context | peps.python.org
Currently, None is the default for both __context__ and __cause__. In order to support raise ... from None (which would set __cause__ to None) we need a different default value for __cause__.
🌐
Python Morsels
pythonmorsels.com › re-raising-exceptions
Re-raising exceptions in Python - Python Morsels
June 10, 2026 - If you'd like to suppress the old exception and entirely replace it with the new one, you should use raise from None. ... Sign up free to track your progress. 1 Deciphering Python's Traceback (most recent call last) 03:39
🌐
GitHub
github.com › williballenthin › python-registry › issues › 76
Return None instead of raising Exception · Issue #76 · williballenthin/python-registry GitHub
March 28, 2017 - When requesting a (sub)key, Registry raises an exception if this key is not found. The same for values. Since actually the easiest way to check if a key exists (implicitly) to call key.subkey() and then the absence of the subkey is not really an exception in that sense. Would you consider replacing the exception-raising with returning None?
Author: williballenthin
🌐
Nmt
infohost.nmt.edu › tcc › help › pubs › python › web › raise-statement.html
23.6. The raise statement: Cause an exception
April 24, 2013 - For an overview, see Section 25, “Exceptions: Error signaling and handling”. ... The first form is equivalent to “raise None,None” and the second form is equivalent to “raise E1, None”. Each form raises an exception of a given type and with a given value.