diff --git a/docs/api_core.rst b/docs/api_core.rst index 32cabf7a..b1cd4025 100644 --- a/docs/api_core.rst +++ b/docs/api_core.rst @@ -1217,8 +1217,9 @@ the reference section on :ref:`class binding `. Raise a Python error of type ``type`` using the format string ``fmt`` interpreted by ``PyErr_FormatV``. - This newly created error is chained on top of an already existing error - status that must be set before calling the function. + If a Python error state was already set prior to calling this method, then + the new error is *chained* on top of the existing one. Otherwise, the + function creates a new error without initializing its ``__cause__`` field. .. cpp:function:: void raise_from(python_error &e, handle type, const char * fmt, ...) diff --git a/include/nanobind/nb_error.h b/include/nanobind/nb_error.h index a4eb8739..5d38c685 100644 --- a/include/nanobind/nb_error.h +++ b/include/nanobind/nb_error.h @@ -148,6 +148,6 @@ class exception : public object { }; NB_CORE void chain_error(handle type, const char *fmt, ...) noexcept; -NB_CORE void raise_from(python_error &e, handle type, const char *fmt, ...); +[[noreturn]] NB_CORE void raise_from(python_error &e, handle type, const char *fmt, ...); NAMESPACE_END(NB_NAMESPACE) diff --git a/src/error.cpp b/src/error.cpp index 8bbd310c..b6c622ad 100644 --- a/src/error.cpp +++ b/src/error.cpp @@ -253,20 +253,21 @@ NAMESPACE_END(detail) static void chain_error_v(handle type, const char *fmt, va_list args) noexcept { #if PY_VERSION_HEX >= 0x030C0000 PyObject *value = PyErr_GetRaisedException(); - check(value, "nanobind::detail::raise_from(): error status is not set!"); #else PyObject *tp = nullptr, *value = nullptr, *traceback = nullptr; PyErr_Fetch(&tp, &value, &traceback); - check(tp, "nanobind::detail::raise_from(): error status is not set!"); - PyErr_NormalizeException(&tp, &value, &traceback); - if (traceback) { - PyException_SetTraceback(value, traceback); - Py_DECREF(traceback); - } + if (tp) { + PyErr_NormalizeException(&tp, &value, &traceback); + if (traceback) { + PyException_SetTraceback(value, traceback); + Py_DECREF(traceback); + } - Py_DECREF(tp); + Py_DECREF(tp); + tp = traceback = nullptr; + } #endif #if !defined(PYPY_VERSION) @@ -278,6 +279,9 @@ static void chain_error_v(handle type, const char *fmt, va_list args) noexcept { Py_DECREF(exc_str); #endif + if (!value) + return; + PyObject *value_2 = nullptr; #if PY_VERSION_HEX >= 0x030C0000 value_2 = PyErr_GetRaisedException();