diff --git a/src/embed_tests/TestPythonException.cs b/src/embed_tests/TestPythonException.cs index a5c2353a6..9a3343460 100644 --- a/src/embed_tests/TestPythonException.cs +++ b/src/embed_tests/TestPythonException.cs @@ -113,6 +113,19 @@ public void InnerIsEmptyWithNoCause() Assert.IsNull(ex.InnerException); } + [Test] + public void TestErrorSetWithoutValue() + { + using var _ = Py.GIL(); + // what PyErr_SetNone does, as C extensions use it: the error's value stays NULL until it is normalized + Runtime.Runtime.PyErr_SetObject(Exceptions.ValueError.Reference, BorrowedReference.Null); + + var ex = Assert.Throws(() => PythonException.ThrowLastAsClrException()); + + Assert.AreEqual("ValueError", ex.Type.Name); + Assert.IsTrue(Runtime.Runtime.PyErr_Occurred().IsNull); + } + [Test] public void TestPythonExceptionFormat() { diff --git a/src/runtime/PythonException.cs b/src/runtime/PythonException.cs index 129668239..9f26e3a8d 100644 --- a/src/runtime/PythonException.cs +++ b/src/runtime/PythonException.cs @@ -111,10 +111,11 @@ internal static PythonException FetchCurrentRaw() try { - var normalizedValue = new NewReference(value.Borrow()); + // an error set without a value, as PyErr_SetNone does, only gets one once normalized + var normalizedValue = new NewReference(value.BorrowNullable(), canBeNull: true); Runtime.PyErr_NormalizeException(type: ref type, val: ref normalizedValue, tb: ref traceback); - return FromPyErr(typeRef: type.Borrow(), valRef: value.Borrow(), nValRef: normalizedValue.Borrow(), tbRef: traceback.BorrowNullable(), out dispatchInfo); + return FromPyErr(typeRef: type.Borrow(), valRef: value.IsNull() ? normalizedValue.Borrow() : value.Borrow(), nValRef: normalizedValue.Borrow(), tbRef: traceback.BorrowNullable(), out dispatchInfo); } finally {