BaseException

Every exception inherits args, tracebacks, chaining and notes from here — but your own exceptions should subclass Exception, not this.

InheritsBaseException
Base classPython 3 (all)Live demo
BaseException(*args)
Raised by
nothing directly — it is the root class
Message
str(e): '' for no args, the arg for one, repr(args) for more
Quick fix
Subclass Exception; catch Exception, not BaseException
Watch out
bare except: and except BaseException also catch Ctrl+C and sys.exit()

Demo

Live evaluation
Build an exception from comma-separated arguments and compare e.args with str(e).
Try:
Inputs
argslist[str]comma-separated, empty for none
Code
e = BaseException(*['disk full'])
(e.args, str(e))
Result
(('disk full',), 'disk full')

In Raise, watch str(e) change shape: one argument prints as itself, two print as the repr of the whole tuple, none prints as an empty string. In Handle, KeyboardInterrupt, SystemExit and GeneratorExit all fall through except Exception — that is exactly why they inherit from BaseException. Type an unknown name and the KeyError from the dict lookup is caught by except Exception instead.

Constructor

NameTypeRequiredDescription
*argsobjectnoAny positional arguments, stored unchanged in e.args. Keyword arguments are rejected: BaseException() takes no keyword arguments.

Attributes

AttributeTypeMeaning
argstupleThe positional constructor arguments, unchanged. str(e) is built from it.
__traceback__traceback | NoneThe traceback object; None until the exception is raised. Writable.
__cause__BaseException | NoneExplicit chaining — set by raise NewError(...) from original.
__context__BaseException | NoneImplicit chaining — the exception that was being handled when this one was raised. Set automatically.
__suppress_context__boolTrue after raise ... from ... (including from None): the traceback then hides __context__.
__notes__list[str]Extra lines shown after the message in the traceback. Created by the first add_note() call (3.11+).
add_note(note)methodAppend a string to __notes__. A non-string raises TypeError. (3.11+)
with_traceback(tb)methodSet __traceback__ to tb and return the same exception object.

Common patterns

Top-level catch that still lets Ctrl+C through
Catch Exception for "anything went wrong" handling. KeyboardInterrupt and SystemExit keep working because they are not Exceptions.
try:
    run()
except Exception as e:
    log.error('run failed: %r', e)
Chain on purpose with from
Translate a low-level error but keep it visible as __cause__ ("The above exception was the direct cause of…").
try:
    cfg = json.loads(text)
except ValueError as e:
    raise ConfigError('config.json is not valid JSON') from e
Add context with a note (3.11+)
Attach where the error happened without changing its type or message, then re-raise.
for n, line in enumerate(lines, 1):
    try:
        parse(line)
    except ValueError as e:
        e.add_note(f'line {n}: {line!r}')
        raise
Clean up on anything, then re-raise
The one legitimate use of except BaseException: run cleanup and re-raise, so Ctrl+C and sys.exit() still work.
try:
    work()
except BaseException:
    rollback()
    raise

Examples

1. args keeps every argument
ValueError('bad size', 42).args
Returns
('bad size', 42)
2. str() depends on how many args
[str(Exception()), str(Exception('x')), str(Exception('x', 1))]
Returns
['', 'x', "('x', 1)"]
3. Notes appear under the message
e = ValueError('bad row') e.add_note('while reading line 3') raise e
Returns
ValueError: bad row while reading line 3
4. raise ... from sets __cause__
try: try: int('x') except ValueError as e: raise RuntimeError('config broken') from e except RuntimeError as err: r = (type(err.__cause__).__name__, err.__suppress_context__) r
Returns
('ValueError', True)
5. Raising inside except sets __context__
try: try: {}['k'] except KeyError: raise ValueError('lookup failed') except ValueError as err: r = (repr(err.__context__), err.__cause__) r
Returns
("KeyError('k')", None)
6. except Exception misses KeyboardInterrupt
try: try: raise KeyboardInterrupt except Exception: r = 'Exception' except BaseException as e: r = type(e).__name__ r
Returns
'KeyboardInterrupt'
7. __traceback__ is None until raised
e = ValueError('x') before = e.__traceback__ try: raise e except ValueError: after = type(e.__traceback__).__name__ (before, after)
Returns
(None, 'traceback')
8. with_traceback returns the same object
e = ValueError('x') e.with_traceback(None) is e
Returns
True

Pitfalls

1. A bare except swallows sys.exit()
except: (and except BaseException:) catches SystemExit, so the program keeps running after it asked to exit. except Exception lets it through.
bare except
import sys
def main():
    try:
        sys.exit(2)
    except:
        return 'kept running'
main()
'kept running'
except Exception
import sys
def main():
    try:
        sys.exit(2)
    except Exception:
        return 'kept running'
try:
    main()
except SystemExit as e:
    r = f'exiting with status {e.code}'
r
'exiting with status 2'
2. Custom exceptions derived from BaseException
Frameworks and libraries catch Exception for error handling. An error class derived from BaseException slips past all of them.
(BaseException)
class AppError(BaseException):
    pass
try:
    try:
        raise AppError('db down')
    except Exception:
        r = 'handled'
except BaseException as e:
    r = f'escaped: {e!r}'
r
"escaped: AppError('db down')"
(Exception)
class AppError(Exception):
    pass
try:
    try:
        raise AppError('db down')
    except Exception:
        r = 'handled'
except BaseException as e:
    r = f'escaped: {e!r}'
r
'handled'
3. Logging str(e) can log nothing
An exception raised without arguments has an empty str(). Log repr(e) (or the type name) so the log line says what happened.
f'{e}'
try:
    raise TimeoutError
except Exception as e:
    msg = f'failed: {e}'
msg
'failed: '
f'{e!r}'
try:
    raise TimeoutError
except Exception as e:
    msg = f'failed: {e!r}'
msg
'failed: TimeoutError()'

When to use

Use it
  • Reading the shared attributes: args, __cause__, __context__, __notes__, __traceback__
  • except BaseException: only to clean up and re-raise
  • Type hints for code that accepts any exception object (loggers, reporters)
Reach for something else
  • Base class for your own errors → subclass Exception
  • Catch-all error handling → except Exception
  • Bare except: — it is except BaseException in disguise

Notes

CPython impl
Objects/exceptions.c — BaseException_str: empty for no args, str(args[0]) for one, str(args) otherwise
Direct subclasses
Exception, BaseExceptionGroup, GeneratorExit, KeyboardInterrupt, SystemExit
Bare except
except: catches exactly what except BaseException: catches
Traceback display
__cause__ is shown as "direct cause", __context__ as "During handling of the above exception…" unless __suppress_context__ is True

FAQ

A bare except: catches everything derived from BaseException — including KeyboardInterrupt (Ctrl+C), SystemExit (sys.exit()) and GeneratorExit. except Exception catches only ordinary errors and lets those three through, so the program can still be interrupted and can still exit. Use except Exception for catch-all handling; use a bare except or except BaseException only when you re-raise.

History

3.11
add_note() and the __notes__ attribute were added.