Errors on Android don't have a message: `Unknown std::runtime_error error`
What's happening?
On Android, errors / exceptions don't have a proper message, and always resort to Unknown T error (e.g. Unknown std::runtime_error error) instead of using it's message (what()).
The same goes for Promise<T>.
I can't really figure out why this is happening - my best guess is that there is some ABI issue with the libc++ standard used by Android NDK, and since errors in Nitro are implemented using std::exception_ptr, the methods current_exception()/rethrow_exception(..) are broken in Android.
I created an issue in the react-native repo: https://github.com/facebook/react-native/issues/48027
Reproduceable Code
class MyHybrid: public MyHybridSpec {
// ...
public:
void someFunc() override {
throw std::runtime_error("my message!");
}
};
Relevant log output
iOS ✅:
MyHybrid.someFunc(): my message!
Android ❌:
MyHybrid.someFunc() threw an unknown std::runtime_error error.
Device
Huawei P10
Nitro Modules Version
0.18.1
Nitrogen Version
0.18.1
Can you reproduce this issue in the Nitro Example app here?
Yes, I can reproduce the same issue in the Example app here
Additional information
- [ ] I am using Expo
- [ ] I am using Nitrogen (nitro-codegen)
- [X] I have read and followed the Troubleshooting Guide.
- [ ] I created a reproduction PR to reproduce this issue here in the nitro repo. (See Contributing for more information)
- [X] I searched for similar issues in this repository and found none.
cc @Szymon20000
Actually this is a react-native bug, not a Nitro bug. It can be reproduced in a blank new react-native 0.76 or 0.77 app. https://github.com/facebook/react-native/issues/48027
Since this is a RN bug, do you know any issue number/link on their repo that tracks this?
yea see my comment directly above yours
I don't know how I missed that... sorry. Thanks for the reply.
this also show on ios platform with [email protected]
Error: `NitroModulesProxy.createHybridObject(...)` threw an unknown std::runtime_error error.
@iwater i cannot reproduce this on iOS - which Nitro version? can you reproduce this in the NitroExample app here?
0.20.1,I just use template folder code as library template and add Math code from doc, then got that error message , I just put that code on https://github.com/iwater/react-native-nitro-crypto2
sorry, I just create a new project, it can show detail error message now.
Is unknown facebook::jni::JniException error related to this issue? For example:
(NOBRIDGE) ERROR [Error: `Math.throwError(...)` threw an unknown facebook::jni::JniException error.]
The Kotlin class is:
package com.margelo.nitro.math
class HybridMath : HybridMathSpec() {
override val memorySize = 0L
override fun throwError() {
throw Error("THIS IS ERROR!")
}
}
Yup, same story here.
Unfortunately caused by the new SoLoader merging changes introduced in RN 0.76. Not sure if this only affects Nitro Modules or also (C++) TurboModules as well.
@Nlcke If you can try what @cortinico suggested in this comment, that would be a huge help.
Unfortunately caused by the new SoLoader merging changes introduced in RN 0.76
Has this been confirmed as being the root cause?
Not 100%, no. Should've phrased this differently. But I'm pretty sure we can figure that out if we try your suggestion in your comment.
I am experiencing the same on iOS. Simply doing something along the lines of
std::shared_ptr<margelo::nitro::Promise<void>> ClassName::asyncMethod() {
return Promise<void>::async([this]() -> void {
throw std::runtime_error("GENERIC RUNTIME ERROR");
});
}
Throws an [Error: Unknown std::runtime_error error.]. In other cases of actual failures, I get Unknown St13runtime_error error.
[email protected] [email protected]
Some info from our podspec:
s.pod_target_xcconfig = {
'USE_HEADERMAP' => 'YES',
'DEFINES_MODULE' => 'YES',
'CLANG_CXX_LANGUAGE_STANDARD' => 'c++20',
'SWIFT_COMPILATION_MODE' => 'wholemodule',
'GCC_PREPROCESSOR_DEFINITIONS' => '$(inherited) FOLLY_NO_CONFIG FOLLY_CFG_NO_COROUTINES MINIAUDIO_IMPLEMENTATION MA_NO_RUNTIME_LINKING'
}
s.frameworks =
"Foundation",
"AVFoundation",
"AVFAudio",
"CoreFoundation",
"CoreAudio",
"AudioToolbox"
s.subspec "MiniAudio" do |ss|
...
ss.compiler_flags = "-x objective-c -lpthread -lm"
end
@thecynicalpaul I'd need a repro for that. The NitroExample app tests exactly this code and it works just fine. https://github.com/mrousavy/nitro/blob/41d94a5ddea6243216465aec29331eddf58406d1/packages/react-native-nitro-image/cpp/HybridTestObjectCpp.cpp#L366-L368
If you pass custom compiler_flags you'd likely want to enable -fexceptions and -frtti tho.
I am also getting the error message: threw an unknown facebook::jni::JniException error instead of actual error which I throw in Kotlin.
Hope we can fix this, else it would be really hard to debug any error as a user or developer.
Hope we can fix this
As already mentioned, this is a bug in react-native.
Using [email protected], I can confirm that errors have messages now! No idea how to patch for current RN versions though, applying this commit doesn't seem to have changed anything, even after a rebuild.
I can confirm that errors have messages now! No idea how to patch for current RN versions though, applying this commit doesn't seem to have changed anything, even after a rebuild.
It's not a single commit sadly, it's a rather complicated series of commits.
Nice to hear it is working in 0.80 now though. Great to see the ecosystem progressing and improving so fast - thanks again @cortinico. ❤
I have found this patch to workaround this bug
diff --git a/node_modules/react-native-nitro-modules/cpp/core/HybridFunction.hpp b/node_modules/react-native-nitro-modules/cpp/core/HybridFunction.hpp
index aefd987..c2e06fb 100644
--- a/node_modules/react-native-nitro-modules/cpp/core/HybridFunction.hpp
+++ b/node_modules/react-native-nitro-modules/cpp/core/HybridFunction.hpp
@@ -23,6 +23,10 @@ struct JSIConverter;
#include <string>
#include <type_traits>
+#ifdef ANDROID
+#include <fbjni/fbjni.h>
+#endif
+
namespace margelo::nitro {
using namespace facebook;
@@ -118,6 +122,10 @@ public:
std::string funcName = getHybridFuncFullName<THybrid>(kind, name, hybridInstance.get());
std::string message = exception.what();
throw jsi::JSError(runtime, funcName + ": " + message);
+ } catch (const jni::JniException& exception) {
+ std::string funcName = getHybridFuncFullName<THybrid>(kind, name, hybridInstance.get());
+ std::string message = exception.what();
+ throw jsi::JSError(runtime, funcName + ": " + message);
#pragma clang diagnostic pop
#endif
} catch (...) {
But it's still workaround... best would be upgrading to react-native 0.80 once it's released
I'm also seeing this from swift as well. I tried running the example app to see if i can repro in isolation, but haven't gotten it to build yet. I also tried the latest rc (4), but had unrelated build issues. Hopefully 80 is released in the near future.
I'm also seeing this from swift as well.
This is an Android only bug, this does not happen in Swift. I just tested it again to verify, all tests run on iOS - both C++ and Swift Hybrid Object tests.
On ios, I'm seeing these unknown errors when throwing from within a promise like throw RuntimeError.error(withMessage: "Failed creating recognizer"). I'll keep digging if it's a different issue.
This 100% works in the example in Swift here; https://github.com/mrousavy/nitro/blob/88239361578b520adeda69e675ff2e72572b9021/packages/react-native-nitro-image/ios/HybridTestObjectSwift.swift#L262-L266
Can you share your code? Or try to get the example to run and modify on your end. You just need bun bootstrap and then open it in Xcode
I just got the example to build and all tests pass. The code is private, but if I can minimize the repro, I'll make a repo to share it. I'm comparing the two projects to see if I have any odd configuration that would cause a different result, but it's basically just a simple module created from npx create-nitro-module@latest.
I've done some debugging, and found that after removing the #ifdef ANDROID guard, that branch is hit and the error message is propagated. So it seems that perhaps an rtti issue where a runtime_error is not considered an exception for whatever reason. I'm using static frameworks (due to firebase limitation mentioned in other issues), and perhaps that affects it. I can try using a patch for now until I solve it.
Fixed in https://github.com/mrousavy/nitro/pull/741 (RN 80+)
@mrousavy I've confirmed on ios that this happens when I enable static linking in my project, but still can't narrow it down as to why. I ran the example project again today with static linking and it worked fine, so it's got to be something to do with some other compiler flags being propagated.
I'd like to provide a repro, but I'm having trouble finding what would even be likely to cause it. I'm currently comparing the compiler settings in pbxproj to see if somehow rtti is being disabled or the wrong std is being used (my only working guesses so far as to why the exception type check isn't being hit). Any tips on where to look would be appreciated as I'm not doing anything too unusual and I assume others will hit this eventually.