From 6926fe8c9d8a89fd72c68ae202ea09da735bb931 Mon Sep 17 00:00:00 2001 From: chmjkb Date: Thu, 21 May 2026 11:25:42 +0200 Subject: [PATCH] fix: make native error of type Error instead of Object --- .../rnexecutorch/RnExecutorchInstaller.h | 13 +- .../host_objects/ModelHostObject.h | 135 +++++++++--------- 2 files changed, 72 insertions(+), 76 deletions(-) diff --git a/packages/react-native-executorch/common/rnexecutorch/RnExecutorchInstaller.h b/packages/react-native-executorch/common/rnexecutorch/RnExecutorchInstaller.h index d130719a8d..887a8ac0ea 100644 --- a/packages/react-native-executorch/common/rnexecutorch/RnExecutorchInstaller.h +++ b/packages/react-native-executorch/common/rnexecutorch/RnExecutorchInstaller.h @@ -93,14 +93,11 @@ class RnExecutorchInstaller { } catch (const rnexecutorch::RnExecutorchError &e) { auto code = e.getNumericCode(); auto msg = std::string(e.what()); - jsCallInvoker->invokeAsync([promise, code, - msg](jsi::Runtime &rt) { - jsi::Object errorData(rt); - errorData.setProperty(rt, "code", code); - errorData.setProperty( - rt, "message", jsi::String::createFromUtf8(rt, msg)); - promise->reject(jsi::Value(rt, std::move(errorData))); - }); + jsCallInvoker->invokeAsync( + [promise, code, msg](jsi::Runtime &rt) { + promise->reject( + makeRnExecutorchErrorValue(rt, code, msg)); + }); } catch (const std::exception &e) { jsCallInvoker->invokeAsync( [promise, msg = std::string(e.what())]() { diff --git a/packages/react-native-executorch/common/rnexecutorch/host_objects/ModelHostObject.h b/packages/react-native-executorch/common/rnexecutorch/host_objects/ModelHostObject.h index 1c29091228..4b1367ce3a 100644 --- a/packages/react-native-executorch/common/rnexecutorch/host_objects/ModelHostObject.h +++ b/packages/react-native-executorch/common/rnexecutorch/host_objects/ModelHostObject.h @@ -28,6 +28,19 @@ namespace rnexecutorch { +inline jsi::Value makeRnExecutorchErrorValue(jsi::Runtime &runtime, + int32_t code, + const std::string &message) { + auto errorObj = + runtime.global() + .getPropertyAsFunction(runtime, "Error") + .callAsConstructor(runtime, + jsi::String::createFromUtf8(runtime, message)) + .asObject(runtime); + errorObj.setProperty(runtime, "code", code); + return jsi::Value(std::move(errorObj)); +} + template class ModelHostObject : public JsiHostObject { public: explicit ModelHostObject(const std::shared_ptr &model, @@ -252,11 +265,8 @@ template class ModelHostObject : public JsiHostObject { return jsi_conversion::getJsiValue(std::move(result), runtime); } } catch (const RnExecutorchError &e) { - jsi::Object errorData(runtime); - errorData.setProperty(runtime, "code", e.getNumericCode()); - errorData.setProperty(runtime, "message", - jsi::String::createFromUtf8(runtime, e.what())); - throw jsi::JSError(runtime, jsi::Value(runtime, std::move(errorData))); + throw jsi::JSError(runtime, makeRnExecutorchErrorValue( + runtime, e.getNumericCode(), e.what())); } catch (const std::exception &e) { throw jsi::JSError(runtime, e.what()); } catch (...) { @@ -322,11 +332,8 @@ template class ModelHostObject : public JsiHostObject { return jsi_conversion::getJsiValue(std::move(result), runtime); } } catch (const RnExecutorchError &e) { - jsi::Object errorData(runtime); - errorData.setProperty(runtime, "code", e.getNumericCode()); - errorData.setProperty(runtime, "message", - jsi::String::createFromUtf8(runtime, e.what())); - throw jsi::JSError(runtime, jsi::Value(runtime, std::move(errorData))); + throw jsi::JSError(runtime, makeRnExecutorchErrorValue( + runtime, e.getNumericCode(), e.what())); } catch (const std::exception &e) { throw jsi::JSError(runtime, e.what()); } catch (...) { @@ -359,60 +366,55 @@ template class ModelHostObject : public JsiHostObject { // We need to dispatch a thread if we want the function to be // asynchronous. In this thread all accesses to jsi::Runtime need to // be done via the callInvoker. - threads::GlobalThreadPool::detach([model = this->model, - callInvoker = this->callInvoker, - promise, - argsConverted = - std::move(argsConverted)]() { - try { - if constexpr (std::is_void_v) { - // For void functions, just call the function and resolve - // with undefined - std::apply(std::bind_front(FnPtr, model), - std::move(argsConverted)); - callInvoker->invokeAsync([promise](jsi::Runtime &runtime) { - promise->resolve(jsi::Value::undefined()); - }); - } else { - // For non-void functions, capture the result and convert - // it - auto result = std::apply(std::bind_front(FnPtr, model), - std::move(argsConverted)); - // The result is copied. It should either be quickly - // copiable, or passed with a shared_ptr. - callInvoker->invokeAsync( - [promise, result](jsi::Runtime &runtime) { - promise->resolve(jsi_conversion::getJsiValue( - std::move(result), runtime)); - }); - } - } catch (const RnExecutorchError &e) { - auto code = e.getNumericCode(); - auto msg = std::string(e.what()); - callInvoker->invokeAsync([code, msg, - promise](jsi::Runtime &runtime) { - jsi::Object errorData(runtime); - errorData.setProperty(runtime, "code", code); - errorData.setProperty( - runtime, "message", - jsi::String::createFromUtf8(runtime, msg)); - promise->reject(jsi::Value(runtime, std::move(errorData))); - }); - return; - } catch (const std::exception &e) { - callInvoker->invokeAsync([e = std::move(e), promise]() { - promise->reject(std::string(e.what())); - }); - return; - } catch (...) { - callInvoker->invokeAsync([promise]() { - promise->reject(std::string("Unknown error")); + threads::GlobalThreadPool::detach( + [model = this->model, callInvoker = this->callInvoker, promise, + argsConverted = std::move(argsConverted)]() { + try { + if constexpr (std::is_void_v) { + // For void functions, just call the function and resolve + // with undefined + std::apply(std::bind_front(FnPtr, model), + std::move(argsConverted)); + callInvoker->invokeAsync( + [promise](jsi::Runtime &runtime) { + promise->resolve(jsi::Value::undefined()); + }); + } else { + // For non-void functions, capture the result and convert + // it + auto result = std::apply(std::bind_front(FnPtr, model), + std::move(argsConverted)); + // The result is copied. It should either be quickly + // copiable, or passed with a shared_ptr. + callInvoker->invokeAsync( + [promise, result](jsi::Runtime &runtime) { + promise->resolve(jsi_conversion::getJsiValue( + std::move(result), runtime)); + }); + } + } catch (const RnExecutorchError &e) { + auto code = e.getNumericCode(); + auto msg = std::string(e.what()); + callInvoker->invokeAsync( + [code, msg, promise](jsi::Runtime &runtime) { + promise->reject( + makeRnExecutorchErrorValue(runtime, code, msg)); + }); + return; + } catch (const std::exception &e) { + callInvoker->invokeAsync([e = std::move(e), promise]() { + promise->reject(std::string(e.what())); + }); + return; + } catch (...) { + callInvoker->invokeAsync([promise]() { + promise->reject(std::string("Unknown error")); + }); + return; + } }); - return; - } - }); } catch (...) { promise->reject(std::string( "Couldn't parse JS arguments in a native function")); @@ -427,11 +429,8 @@ template class ModelHostObject : public JsiHostObject { model->unload(); thisValue.asObject(runtime).setExternalMemoryPressure(runtime, 0); } catch (const RnExecutorchError &e) { - jsi::Object errorData(runtime); - errorData.setProperty(runtime, "code", e.getNumericCode()); - errorData.setProperty(runtime, "message", - jsi::String::createFromUtf8(runtime, e.what())); - throw jsi::JSError(runtime, jsi::Value(runtime, std::move(errorData))); + throw jsi::JSError(runtime, makeRnExecutorchErrorValue( + runtime, e.getNumericCode(), e.what())); } catch (const std::exception &e) { throw jsi::JSError(runtime, e.what()); } catch (...) {