Skip to main content

Python/errors.c

cpython 3.14 @ ab2d84fe1023/Python/errors.c

Python/errors.c is the core exception signalling layer. It owns the thread-state exception fields and every function that sets, tests, clears, or formats an exception in the C runtime.

Map

LinesSymbolRole
1-200PyErr_Restore, PyErr_SetObject, PyErr_SetStringSet the current exception
201-450PyErr_Occurred, PyErr_Clear, PyErr_Fetch, PyErr_NormalizeTest and retrieve
451-700PyErr_Format, PyErr_FormatVString-formatted exception messages
701-950PyErr_SetFromErrno, PyErr_SetFromWindowsErrOS-error helpers
951-1200Chaining machinery__context__, __cause__, __suppress_context__
1201-1680PyErr_WriteUnraisable, warning machineryBackground error reporting

Reading

PyErr_SetObject

// CPython: Python/errors.c:68 PyErr_SetObject
void
PyErr_SetObject(PyObject *exception, PyObject *value)
{
PyThreadState *tstate = _PyThreadState_GET();
_PyErr_SetObject(tstate, exception, value);
}

The exception is stored directly in tstate->current_exception (Python 3.12+). Earlier versions used three separate fields (exc_type, exc_value, exc_traceback); the 3.12 consolidation stores a single normalized exception object.

PyErr_Normalize

Normalization ensures exc_value is an instance of exc_type. If exc_value is not yet an instance (for example a raw string was passed), normalization calls exc_type(exc_value) and replaces the stored value. This is what allows raise ValueError("msg") to work with either a class or an instance.

// CPython: Python/errors.c:364 PyErr_NormalizeException
void
PyErr_NormalizeException(PyObject **exc, PyObject **val, PyObject **tb)
{
...
if (!PyExceptionInstance_Check(*val)) {
PyObject *args;
if (*val == Py_None || *val == NULL)
args = PyTuple_New(0);
else if (PyTuple_Check(*val))
args = *val;
else
args = PyTuple_Pack(1, *val);
*val = _PyObject_CallOneArg(*exc, args);
...
}
...
}

Chained exceptions

When an exception is raised inside an except block, Python/errors.c sets __context__ automatically. raise X from Y additionally sets __cause__ and clears __suppress_context__. The context chain is walked by the traceback printer.

PyErr_WriteUnraisable

Used for exceptions that occur in destructors or tp_finalize callbacks where there is no Python caller to propagate to. It calls sys.unraisablehook if defined, then falls back to writing to sys.stderr.

gopy notes

errors.Raise in gopy maps to _PyErr_SetObject. The normalized exception object model is handled in objects/. The chained-exception fields (__context__, __cause__) are set by the vm layer during RAISE_VARARGS handling.