From eb8e27abced19b1aa0d039d946c3570f019ad225 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Larch?= Date: Wed, 21 Oct 2026 21:03:28 +0200 Subject: [PATCH] Throw the named error type from JSError.Throw*Error(string) JSError.ThrowTypeError, ThrowRangeError and ThrowSyntaxError (with and without a code) all called JSRuntime.ThrowError, so JS received a plain Error instead of a TypeError / RangeError / SyntaxError. Call the matching runtime method instead. Fixes #509. Co-Authored-By: Claude Opus 5.5 --- src/NodeApi/JSError.cs | 12 ++++---- test/NodejsEmbeddingTests.cs | 55 ++++++++++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+), 6 deletions(-) diff --git a/src/NodeApi/JSError.cs b/src/NodeApi/JSError.cs index 33437ae9..74cf119f 100644 --- a/src/NodeApi/JSError.cs +++ b/src/NodeApi/JSError.cs @@ -290,22 +290,22 @@ public static void ThrowError(string code, string message) => JSValue.GetCurrentRuntime(out napi_env env).ThrowError(env, code, message); public static void ThrowTypeError(string message) - => JSValue.GetCurrentRuntime(out napi_env env).ThrowError(env, code: null, message); + => JSValue.GetCurrentRuntime(out napi_env env).ThrowTypeError(env, code: null, message); public static void ThrowTypeError(string code, string message) - => JSValue.GetCurrentRuntime(out napi_env env).ThrowError(env, code, message); + => JSValue.GetCurrentRuntime(out napi_env env).ThrowTypeError(env, code, message); public static void ThrowRangeError(string message) - => JSValue.GetCurrentRuntime(out napi_env env).ThrowError(env, code: null, message); + => JSValue.GetCurrentRuntime(out napi_env env).ThrowRangeError(env, code: null, message); public static void ThrowRangeError(string code, string message) - => JSValue.GetCurrentRuntime(out napi_env env).ThrowError(env, code, message); + => JSValue.GetCurrentRuntime(out napi_env env).ThrowRangeError(env, code, message); public static void ThrowSyntaxError(string message) - => JSValue.GetCurrentRuntime(out napi_env env).ThrowError(env, code: null, message); + => JSValue.GetCurrentRuntime(out napi_env env).ThrowSyntaxError(env, code: null, message); public static void ThrowSyntaxError(string code, string message) - => JSValue.GetCurrentRuntime(out napi_env env).ThrowError(env, code, message); + => JSValue.GetCurrentRuntime(out napi_env env).ThrowSyntaxError(env, code, message); /// /// Gets a JS error stack trace that also includes a .NET stack trace, diff --git a/test/NodejsEmbeddingTests.cs b/test/NodejsEmbeddingTests.cs index 1785decc..cc5fbc78 100644 --- a/test/NodejsEmbeddingTests.cs +++ b/test/NodejsEmbeddingTests.cs @@ -288,6 +288,61 @@ public void ThrowErrorFromCallback(string message) }); } + [Theory] + [InlineData("Error", null)] + [InlineData("Error", "ERR_TEST")] + [InlineData("TypeError", null)] + [InlineData("TypeError", "ERR_TEST")] + [InlineData("RangeError", null)] + [InlineData("RangeError", "ERR_TEST")] + [InlineData("SyntaxError", null)] + [InlineData("SyntaxError", "ERR_TEST")] + public void ThrowTypedError(string errorType, string? code) + { + using NodeEmbeddingThreadRuntime nodejs = CreateNodeEmbeddingThreadRuntime(); + + nodejs.Run(() => + { + JSValue.Global.SetProperty("throwError", JSValue.CreateFunction("throwError", (_) => + { + Action throwWithoutCode = errorType switch + { + "Error" => JSError.ThrowError, + "TypeError" => JSError.ThrowTypeError, + "RangeError" => JSError.ThrowRangeError, + "SyntaxError" => JSError.ThrowSyntaxError, + _ => throw new ArgumentOutOfRangeException(nameof(errorType)), + }; + Action throwWithCode = errorType switch + { + "Error" => JSError.ThrowError, + "TypeError" => JSError.ThrowTypeError, + "RangeError" => JSError.ThrowRangeError, + "SyntaxError" => JSError.ThrowSyntaxError, + _ => throw new ArgumentOutOfRangeException(nameof(errorType)), + }; + + if (code == null) throwWithoutCode("test"); + else throwWithCode(code, "test"); + return JSValue.Undefined; + })); + + JSValue error = JSValue.RunScript(""" + (() => { + try { throwError(); } catch (e) { return e; } + return null; + })() + """); + Assert.True(error.IsObject()); + Assert.Equal(errorType, (string)error["name"]); + Assert.True((bool)JSValue.RunScript( + $"(e) => e instanceof {errorType}").Call(JSValue.Undefined, error)); + Assert.Equal("test", (string)error["message"]); + if (code == null) Assert.True(error["code"].IsUndefined()); + else Assert.Equal(code, (string)error["code"]); + }); + } + [Fact] public async Task WorkerIsMainThread() {