From e3471b1e0b9560b0e282d1c2833506199c8ef0e7 Mon Sep 17 00:00:00 2001 From: Eduardo Speroni Date: Mon, 5 Oct 2026 16:05:09 -0300 Subject: [PATCH] fix(worker): carry the deserialization failure in a worker's messageerror data A message a worker (or its parent) cannot read fires messageerror with data === null, while the same failure on a MessagePort delivers the thrown exception as data (NativeMessagePort::Drain), which is also what Node hands worker.on('messageerror'). The node:worker_threads shim forwards event.data unchanged, so its Worker and parentPort surfaces received null where Node gives the Error. Worker::OnMessageCallback now mirrors the port path: the caught exception when there is one, null otherwise. --- NativeScript/runtime/Worker.mm | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/NativeScript/runtime/Worker.mm b/NativeScript/runtime/Worker.mm index 875243ac..5e718684 100644 --- a/NativeScript/runtime/Worker.mm +++ b/NativeScript/runtime/Worker.mm @@ -729,11 +729,16 @@ throw NativeScriptException( return; } // HTML: a message that cannot be read still reaches its target, as a - // `messageerror` event carrying nothing, which leaves `data` at the - // null it defaults to. Delivery stores what it is given, so an - // undefined here would surface as undefined. + // `messageerror` event. Its `data` is the failure, the same as a port's + // (NativeMessagePort::Drain) and as what Node hands + // `worker.on("messageerror")`; null when nothing was thrown, since + // delivery stores the payload as given and a bare undefined would + // surface as such. + data = tc.HasCaught() ? tc.Exception() : Local(); + if (data.IsEmpty() || data->IsUndefined()) { + data = v8::Null(isolate); + } tc.Reset(); - data = v8::Null(isolate); ports = Local(); type = "messageerror"; }