Attempting to call setInternalViewAttribute on RUM when it has not been enabled
Describe the bug
Hi, in our datadog error reports, we are experiencing the error:
PlatformException(DatadogSdk:InvalidOperation,
Attempting to call setInternalViewAttribute on RUM when it has not been enabled,
null, null)
The error occurs intermittently on Android only when DatadogNavigationObserver attempts to call markViewFirstBuildComplete() after a navigation event. The error originates from the Android native side guard clause in DatadogRumPlugin.kt:
override fun onMethodCall(call: MethodCall, result: Result) {
if (call.method != "enable" && rum == null) {
result.invalidOperation(
"Attempting to call ${call.method} on RUM when it has not been enabled"
)
return
}
// ...
}
Reproduction steps
The error occurs only on Android devices. It is currently unknown whether the issue also appears on emulators, but it has been confirmed on physical devices.
The bug cannot be consistently reproduced, and the root cause is not yet identified.
SDK logs
No response
Expected behavior
No response
Affected SDK versions
2.11.0
Latest working SDK version
No response
Did you confirm if the latest SDK version fixes the bug?
No
Flutter Version
3.35.4
Setup Type
No response
Device Information
Various Android devices running Android OS version 12-16.
Few of the devices examples would be: Samsung SM-M135FU, Pixel 7 Pro, Pixel 9a
Other relevant information
No response
Hi @rimastide ,
This is very strange. Is there anything unusual about your setup? Is this a hybrid application, are you using multiple isolates, or are you using "Multiple Flutter Engines?" Additionally, do subsequent RUM events work, or once you see this error do all events generate the error?
I have seen this before, and it had to do with some bad logic when Flutter would shutdown plugins during backgrounding / foregrounding, but I was pretty sure we had it fixed. It's possible some changes in Flutter has create a race condition somewhere I wasn't aware of.
If you can give me any tips, I'll see if I can reproduce.
Hi @rimastide ,
This is very strange. Is there anything unusual about your setup? Is this a hybrid application, are you using multiple isolates, or are you using "Multiple Flutter Engines?" Additionally, do subsequent RUM events work, or once you see this error do all events generate the error?
I have seen this before, and it had to do with some bad logic when Flutter would shutdown plugins during backgrounding / foregrounding, but I was pretty sure we had it fixed. It's possible some changes in Flutter has create a race condition somewhere I wasn't aware of.
If you can give me any tips, I'll see if I can reproduce.
Hi @fuzzybinary,
There’s nothing unusual about our setup, apart from having a separate thread for Firebase Messaging - which I believe is fairly common. No multiple Flutter Engines or something else.
From our investigation, the issue only occurs in the setInternalViewAttribute method. It typically appears right after the first screen is displayed (upon navigation), and then continues to appear on subsequent screens throughout the user session. We haven’t observed failures in any other methods - only this one.
It’s also quite rare, occurring for roughly 1 in 10 users.
That’s all the information we currently have, but please let me know if there’s anything specific I can check or provide - I’ll do my best to gather it.
That's the configuration we use (createSdk() always gets called before createNavigationObserver()):
@module
abstract class DatadogModule {
@lazySingleton
RouteObserver<ModalRoute<dynamic>> createNavigationObserver() {
return DatadogNavigationObserver(datadogSdk: DatadogSdk.instance);
}
@lazySingleton
@preResolve
Future<DatadogSdk> createSdk() async {
final configuration = DatadogConfiguration(
clientToken: clientToken,
env: environment,
site: DatadogSite.eu1,
nativeCrashReportEnabled: true,
firstPartyHosts: firstPartyHosts,
rumConfiguration: DatadogRumConfiguration(
applicationId: appId,
traceSampleRate: 10,
sessionSamplingRate: 100,
traceContextInjection: TraceContextInjection.sampled,
),
loggingConfiguration: DatadogLoggingConfiguration(),
)..enableHttpTracking(clientListener: DatadogClientListener());
if (canOverrideFlutterOnError) {
final originalOnError = FlutterError.onError;
FlutterError.onError = (details) {
DatadogSdk.instance.rum?.handleFlutterError(details);
originalOnError?.call(details);
};
}
await DatadogSdk.instance.initialize(
configuration,
TrackingConsent.granted,
);
return DatadogSdk.instance;
}
}
Is setInternalViewAttribute being called as a result from something from Firebase Messaging?
It is very strange that only this call produces the error, but also that it persists even as other calls succeed. We only create one instance of the DatadogSdkPlugin for each FlutterEngine, and it should grab an existing native RumMonitor when it's attached to the engine.
This leads me to believe that there are, actually, two Flutter engines somewhere (probably created by Firebase Messaging), and whether or not the second one has a RUM instance is a race condition on if DatadogSdk.instance.initialize was called prior to that second engine attaching.
I'll try to look into Firebase Messaging and see if that's what's happening. One thing you might try is to initialize the DatadogModule non-lazy immediately at the start of main. This should ensure that the Android native RUM SDK is initialized before Firebase creates its second engine, if that's what's happening.
There is indeed at least 1 additional Flutter Engine attached. It seems that geolocator package (v10.1.0) triggers its creation. Here are the logs:
<...> // app start
D/FlutterGeolocator(10376): Geolocator foreground service connected
D/FlutterGeolocator(10376): Initializing Geolocator services
D/FlutterGeolocator(10376): Flutter engine connected. Connected engine count 1
<...>
E/native_android_datadogrum(10376): rum: null method: enable //'enabled' method called
<...>
E/native_android_datadogrum(10376): rum: com.datadog.android.rum.internal.monitor.DatadogRumMonitor@d05f8bc method: reportLongTask
E/native_android_datadogrum(10376): rum: com.datadog.android.rum.internal.monitor.DatadogRumMonitor@d05f8bc method: startResource
E/native_android_datadogrum(10376): rum: com.datadog.android.rum.internal.monitor.DatadogRumMonitor@d05f8bc method: startResource
<...>
D/FlutterGeolocator(10376): Geolocator foreground service connected
D/FlutterGeolocator(10376): Initializing Geolocator services
D/FlutterGeolocator(10376): Flutter engine connected. Connected engine count 2
<...>
E/native_android_datadogrum(10376): rum: com.datadog.android.rum.internal.monitor.DatadogRumMonitor@d05f8bc method: startView
E/native_android_datadogrum(10376): rum: com.datadog.android.rum.internal.monitor.DatadogRumMonitor@d05f8bc method: setInternalViewAttribute // not reproduced
<...>
Logs are from Android simulator, that specific error has not appeared but we still see several Flutter Engines being created. And we are still investigating if FirebaseMessaging could cause the error too.
Okay, that's good to know. Our usual thing is "we don't support multiple Flutter engines", but it appears more common than I though it was, and can happen without your knowledge.
I'll start looking into how to support this better, though it likely won't be available until our next major version.
It's possible that if you can tell that you're on that second engine (potentially you're not in your main isolate, or you're in an isolate different from the one that initialized Datadog), you might be able to call attachToExisting from Datadog with few to no options. This should hook up the existing global RUM instance to the new Engine / Isolate.