Mapbox Implementation
Mapbox
Mapbox Version
MapboxMaps 11.15.4 / MapboxCommon 24.15.4 (via CocoaPods / @rnmapbox/maps default for 10.2.0)
React Native Version
0.81.1 (New Architecture enabled)
Platform
iOS
@rnmapbox/maps version
10.2.0
Standalone component to reproduce
Crash is intermittent in production (Firebase Crashlytics) and not reliably reproducible in a minimal app yet. Map usage on Home / Device / Estimation screens follows this pattern; access token is set at splash/login via Mapbox.setAccessToken(...).
Crashlytics often reports a non-map screen as the current screen (e.g. a notes list), which suggests MapboxCommon networking continues after the map UI is no longer foregrounded.
import React, { useRef } from 'react';
import { View, StyleSheet } from 'react-native';
import Mapbox, { Camera, StyleURL, UserTrackingMode } from '@rnmapbox/maps';
Mapbox.setAccessToken('YOUR_MAPBOX_ACCESS_TOKEN');
export default function MapCrashExample() {
const refMapView = useRef(null);
const refCamera = useRef(null);
return (
<View style={styles.container}>
<Mapbox.MapView
ref={refMapView}
onDidFinishLoadingMap={() => {}}
onPress={() => {}}
logoEnabled={false}
attributionEnabled={false}
scaleBarEnabled={false}
styleURL={StyleURL.Street}
style={styles.map}>
<Camera
ref={refCamera}
followUserMode={UserTrackingMode.Follow}
animationMode="moveTo"
zoomLevel={8}
/>
</Mapbox.MapView>
</View>
);
}
const styles = StyleSheet.create({
container: { flex: 1 },
map: { flex: 1 },
});
Observed behavior and steps to reproduce
Fatal Exception: mutex lock failed: Invalid argument
Throw site is inside MapboxCommon on a GCD worker queue while writing on the experimental WSS backend. The process then terminates; Crashlytics / other SDKs only appear on the terminate path.
Primary (throwing) stack
Fatal Exception: mutex lock failed: Invalid argument
0 CoreFoundation __exceptionPreprocess
1 libobjc.A.dylib objc_exception_throw
2 CoreFoundation -[NSException initWithCoder:]
3 MapboxCommon mapbox::bindgen::mapbox::common::experimental::wss_backend::Service::write(unsigned long long, std::__1::variant<std::__1::vector<unsigned char, ...>, std::__1::basic_string<char, ...>>&&) + 4000
4 libdispatch.dylib _dispatch_call_block_and_release
5 libdispatch.dylib _dispatch_client_callout
6 libdispatch.dylib _dispatch_lane_serial_drain
7 libdispatch.dylib _dispatch_lane_invoke
8 libdispatch.dylib _dispatch_root_queue_drain_deferred_wlh
9 libdispatch.dylib _dispatch_workloop_worker_thread
10 libsystem_pthread.dylib _pthread_wqthread
11 libsystem_pthread.dylib start_wqthread
### Terminate / Crashlytics recording path (secondary)
Crashed: com.google.firebase.crashlytics.ios.exception
...
FIRCLSTerminateHandler
→ Intercom / StripeTerminal terminate hooks
→ libc++abi std::__terminate
→ objc_exception_throw
→ MapboxCommon mapbox::bindgen::mapbox::common::experimental::wss_backend::Service::write(...)
→ libdispatch (same GCD worker path as above)
**Notes:**
- No app JS frames in the throwing stack.
- No Reanimated / Fabric `ShadowNode` / `nativePropsMutex` frames (this is **not** the known Reanimated ShadowTree race).
- Exception text matches classic C++ `std::system_error` when locking a destroyed/uninitialized mutex (use-after-teardown).
Suspected triggers (unconfirmed): leave a map screen, background the app, style/token lifecycle, or MapboxCommon WSS still writing after teardown.
## Expected behavior
MapboxCommon WSS / networking should not throw a fatal `mutex lock failed: Invalid argument` after map unmount, navigation away from map screens, or app backgrounding.
## Notes / preliminary analysis
1. Searched **rnmapbox/maps** and **mapbox/mapbox-maps-ios** for `"mutex lock failed"`, `wss_backend`, and `Service::write` — **no existing public issue** with this exact frame.
2. Closest historical analogues (different symbols, same teardown/mutex class):
- [mapbox/mapbox-maps-ios#984](https://github.com/mapbox/mapbox-maps-ios/issues/984) — mutex on terminate (`Settings::get` / RunLoop); fixed in Maps 10.3
- [mapbox/mapbox-maps-ios#2174](https://github.com/mapbox/mapbox-maps-ios/issues/2174) — `CleanupManager::cleanup()` on terminate/background (still open)
3. Because the throw is inside the **MapboxCommon binary**, `@rnmapbox/maps` cannot patch `Service::write` directly; likely needs an upstream Maps/Common bump or Mapbox-internal fix. Filing here so maintainers can track / bump default native SDK and/or forward to Mapbox.
4. We are on `@rnmapbox/maps@10.2.0`; newer patch releases exist (e.g. 10.2.10). Happy to try a Maps/Common bump if you recommend a specific `$RNMapboxMapsVersion` / package version for v11.
## Additional links and references
- Native pods: `MapboxMaps (11.15.4)`, `MapboxCommon (24.15.4)`, `rnmapbox-maps (10.2.0)`
- Related (different bug): [rnmapbox/maps#3700](https://github.com/rnmapbox/maps/issues/3700) MapboxCommon location sharedRunLoop CPU (v10 Maps pin) — not this stack
Mapbox Implementation
Mapbox
Mapbox Version
MapboxMaps 11.15.4 / MapboxCommon 24.15.4 (via CocoaPods /
@rnmapbox/mapsdefault for 10.2.0)React Native Version
0.81.1 (New Architecture enabled)
Platform
iOS
@rnmapbox/mapsversion10.2.0
Standalone component to reproduce
Crash is intermittent in production (Firebase Crashlytics) and not reliably reproducible in a minimal app yet. Map usage on Home / Device / Estimation screens follows this pattern; access token is set at splash/login via
Mapbox.setAccessToken(...).Crashlytics often reports a non-map screen as the current screen (e.g. a notes list), which suggests MapboxCommon networking continues after the map UI is no longer foregrounded.
Observed behavior and steps to reproduce
Fatal Exception:
mutex lock failed: Invalid argumentThrow site is inside MapboxCommon on a GCD worker queue while writing on the experimental WSS backend. The process then terminates; Crashlytics / other SDKs only appear on the terminate path.
Primary (throwing) stack
Fatal Exception: mutex lock failed: Invalid argument
0 CoreFoundation __exceptionPreprocess
1 libobjc.A.dylib objc_exception_throw
2 CoreFoundation -[NSException initWithCoder:]
3 MapboxCommon mapbox::bindgen::mapbox::common::experimental::wss_backend::Service::write(unsigned long long, std::__1::variant<std::__1::vector<unsigned char, ...>, std::__1::basic_string<char, ...>>&&) + 4000
4 libdispatch.dylib _dispatch_call_block_and_release
5 libdispatch.dylib _dispatch_client_callout
6 libdispatch.dylib _dispatch_lane_serial_drain
7 libdispatch.dylib _dispatch_lane_invoke
8 libdispatch.dylib _dispatch_root_queue_drain_deferred_wlh
9 libdispatch.dylib _dispatch_workloop_worker_thread
10 libsystem_pthread.dylib _pthread_wqthread
11 libsystem_pthread.dylib start_wqthread
Crashed: com.google.firebase.crashlytics.ios.exception
...
FIRCLSTerminateHandler
→ Intercom / StripeTerminal terminate hooks
→ libc++abi std::__terminate
→ objc_exception_throw
→ MapboxCommon mapbox::bindgen::mapbox::common::experimental::wss_backend::Service::write(...)
→ libdispatch (same GCD worker path as above)