Skip to main content

Objects/exceptions.c

cpython 3.14 @ ab2d84fe1023/Objects/exceptions.c

All Python exceptions inherit from BaseException. This file defines the BaseException type and all 60+ built-in exception types. Most concrete types are thin type objects with no extra fields beyond what BaseException provides. The key fields on BaseException are args (the constructor tuple), tb (__traceback__), cause (__cause__, set by raise X from Y), context (__context__, set implicitly when one exception occurs while another is being handled), and suppress_context (__suppress_context__, True when raise X from None). OSError and SyntaxError subclasses add specialized fields.

Map

LinesSymbolRolegopy
1-200BaseException_init, BaseException_new, BaseException_dealloc, BaseException_traverseBase class lifecycle.objects/exceptions.go:BaseException
200-500BaseException_repr, BaseException_str, BaseException_args, BaseException_with_traceback__repr__, __str__, with_traceback().objects/exceptions.go:baseExceptionRepr
500-900BaseException_get_tb, BaseException_set_tb, BaseException_get_cause, BaseException_set_cause, BaseException_get_context, BaseException_set_context, BaseException_get_suppress_context, BaseException_set_suppress_contextDunder attribute getsets.objects/exceptions.go
900-1200_PyException_AddNote, BaseExceptionGroup type, ExceptionGroup typeNotes (__notes__ list) and exception groups (PEP 654).objects/exceptions.go:AddNote
1200-1800OSError_init, OSError_reduce, OSError_new, errno/strerror/filename getsetsOSError and its errno-dispatched subclasses.objects/exceptions.go:OSError
1800-2400SyntaxError_init, SyntaxError_str, lineno/offset/filename/text/end_lineno/end_offset getsetsSyntaxError with six location fields.objects/exceptions.go:SyntaxError
2400-4000All concrete exception types: ValueError, TypeError, KeyError, StopIteration, SystemExit, ImportError, UnicodeError subclasses, etc.Concrete types, most as thin wrappers.objects/exceptions.go
4000-4586_PyExc_Init, _PyException_SetCause, _PyException_SetContextInterpreter init, cause/context setters used by the eval loop.objects/exceptions.go:Init

Reading

BaseException_init (lines 1 to 200)

cpython 3.14 @ ab2d84fe1023/Objects/exceptions.c#L1-200

__init__ stores the positional args tuple in self->args with a strong reference. __str__ behavior is based on the length of args:

static int
BaseException_init(PyBaseExceptionObject *self, PyObject *args, PyObject *kwds)
{
static char *kwlist[] = {"args", 0};
PyObject *args_ = NULL;
if (!_PyArg_NoKeywords("BaseException", kwds))
return -1;
Py_INCREF(args);
Py_XSETREF(self->args, args);
return 0;
}

static PyObject *
BaseException_str(PyBaseExceptionObject *self)
{
switch (PyTuple_GET_SIZE(self->args)) {
case 0:
return PyUnicode_FromString("");
case 1:
return PyObject_Str(PyTuple_GET_ITEM(self->args, 0));
default:
return PyObject_Str(self->args);
}
}

with_traceback(tb) sets self->tb and returns self to support the chaining idiom raise X.with_traceback(tb):

static PyObject *
BaseException_with_traceback(PyObject *self, PyObject *tb)
{
if (tb != Py_None && !PyTraceBack_Check(tb)) {
PyErr_SetString(PyExc_TypeError,
"__traceback__ must be a traceback or None");
return NULL;
}
Py_XSETREF(((PyBaseExceptionObject *)self)->tb, Py_XNewRef(tb));
return Py_NewRef(self);
}

Cause and context (lines 500 to 900)

cpython 3.14 @ ab2d84fe1023/Objects/exceptions.c#L500-900

__cause__ is set by raise X from Y: the compiler emits RAISE_VARARGS 2 and the eval loop calls _PyException_SetCause(exc, cause). __context__ is set implicitly by the eval loop when an exception escapes while another is already active in the thread state. __suppress_context__ is set True when raise X from None is used, which causes the traceback machinery to omit the "During handling of the above exception, another exception occurred" message:

void
_PyException_SetCause(PyObject *exception, PyObject *cause)
{
PyBaseExceptionObject *exc = (PyBaseExceptionObject *)exception;

Py_XSETREF(exc->cause, Py_XNewRef(cause));
/* raise X from None sets suppress_context so the "during handling"
message is not printed. */
exc->suppress_context = (cause == Py_None) ? 1 : 0;
}

void
_PyException_SetContext(PyObject *exception, PyObject *context)
{
PyBaseExceptionObject *exc = (PyBaseExceptionObject *)exception;
Py_XSETREF(exc->context, Py_XNewRef(context));
}

OSError (lines 1200 to 1800)

cpython 3.14 @ ab2d84fe1023/Objects/exceptions.c#L1200-1800

OSError.__init__ has special-cased 2-arg and 3-arg forms:

static int
OSError_init(PyOSErrorObject *self, PyObject *args, PyObject *kwds)
{
PyObject *myerrno = NULL, *strerror = NULL;
PyObject *filename = NULL, *filename2 = NULL;
Py_ssize_t nargs = PyTuple_GET_SIZE(args);

if (nargs >= 2 && nargs <= 5) {
/* (errno, strerror[, filename[, winerror[, filename2]]]) */
if (!PyArg_UnpackTuple(args, "OSError", 2, 5,
&myerrno, &strerror,
&filename, NULL, &filename2))
return -1;
}
Py_XSETREF(self->myerrno, Py_XNewRef(myerrno));
Py_XSETREF(self->strerror, Py_XNewRef(strerror));
Py_XSETREF(self->filename, Py_XNewRef(filename));
Py_XSETREF(self->filename2, Py_XNewRef(filename2));
...
}

OSError_new dispatches to the correct subclass based on the errno argument when OSError is called directly. The table maps errno values such as ENOENT to FileNotFoundError, EACCES to PermissionError, and so on. This is the mechanism that makes open("missing") raise FileNotFoundError even though the C call returns an OSError.

KeyError.__str__ (lines 2400 and later)

cpython 3.14 @ ab2d84fe1023/Objects/exceptions.c#L2400-2600

KeyError overrides __str__ to use repr(key) instead of str(key) for single-argument exceptions. This ensures string keys are shown with their quotes in tracebacks:

static PyObject *
KeyError_str(PyBaseExceptionObject *self)
{
/* If args is a one-element tuple, use repr of the element. */
if (PyTuple_GET_SIZE(self->args) == 1) {
return PyObject_Repr(PyTuple_GET_ITEM(self->args, 0));
}
return BaseException_str(self);
}

So KeyError("missing") prints as KeyError: 'missing' (with quotes), not KeyError: missing.

_PyExc_Init (lines 4000 and later)

cpython 3.14 @ ab2d84fe1023/Objects/exceptions.c#L4000-4586

Registers all built-in exception types in the builtins module and sets up the inheritance chain. The hierarchy is established by passing explicit tp_base pointers:

BaseException
Exception
ArithmeticError
FloatingPointError, OverflowError, ZeroDivisionError
LookupError
IndexError, KeyError
ValueError
UnicodeError
UnicodeDecodeError, UnicodeEncodeError, UnicodeTranslateError
TypeError, RuntimeError, OSError, ...
GeneratorExit, KeyboardInterrupt, SystemExit

OSError aliases (IOError, EnvironmentError, WindowsError on Windows) are set up here by adding them as attributes of the builtins module pointing to the same type object. _PyExc_Init also calls PyType_Ready on every exception type in dependency order.

gopy mirror

objects/exceptions.go. All 60+ types are defined with __module__ = "builtins". The OSError subclass dispatch uses the same errno-to-type table as CPython. SyntaxError carries the same six location fields (filename, lineno, offset, text, end_lineno, end_offset). _PyException_SetCause and _PyException_SetContext are exported functions called from vm/eval_unwind.go.

CPython 3.14 changes

ExceptionGroup and BaseExceptionGroup added in 3.11 (PEP 654). Exception.add_note() and the __notes__ list attribute added in 3.11. BaseException.__notes__ is lazily created on first call to add_note. UnicodeError subclasses stable since 3.0. The end_lineno and end_offset fields on SyntaxError added in 3.10 for richer error messages.