Repository navigation
bug(ios): one transient CoreLocation error permanently kills location delivery — all later getCurrentPosition calls time out until app relaunch #91
Description
Bug description
On iOS, after one transient CoreLocation failure, every subsequent Geolocation.getCurrentPosition() call in the app session fails with OS-PLUG-GLOC-0010 (timeout) — even when the device gets a GPS fix — until the app process is killed and relaunched.
Root cause (traced through the plugin + IONGeolocationLib source)
CLLocationManager.requestLocation()frequently fails with the transientkCLErrorLocationUnknownon a cold start / indoors withenableHighAccuracy: true. Apple's docs say this error should be ignored while the manager keeps trying.- In
IONGLOCManagerWrapper(ion-ios-geolocation),locationManager(_:didFailWithError:)setscurrentLocation = nil, and thecurrentLocationPublisherpipeline turns that into a failure (tryMapthrowsIONGLOCLocationError.locationUnavailable). - In
GeolocationPlugin.swift→bindLocationPublisher(), that error is handled with:.catch { ... self?.callbackManager?.sendError(.positionUnavailable) return Empty<IONGLOCPositionModel, Never>().eraseToAnyPublisher() }
Empty()completes the stream, so the Combine subscription (locationCancellable) is permanently finished. locationInitializedis never reset, so the guard inbindLocationPublisher()(guard !locationInitialized else { return }) prevents any re-subscription for the rest of the process lifetime.- Net effect: every later
getCurrentPosition()registers its callback andrequestSingleLocation()runs —didUpdateLocationseven fires with a valid fix — but there is no subscriber left to deliver it, so the only thing that ever resolves the call is the timeout timer (locationTimeoutPublisherhas its own, still-alive subscription).
The only recovery paths are relaunching the app, or appDidBecomeActive — which re-binds only when watchCallbacks is non-empty, so plain getCurrentPosition() users never recover.
Steps to reproduce
- iOS device, app using
@capacitor/geolocation8.2.0, location permission granted. - Trigger one transient CoreLocation failure (easiest: cold GPS start indoors with
enableHighAccuracy: trueand a short-ish timeout; first call after boot/standby often does it) → call rejects withOS-PLUG-GLOC-0002. - Move somewhere with good GPS, call
getCurrentPosition()repeatedly. - Every call now rejects with
OS-PLUG-GLOC-0010("Could not obtain location in time") regardless of signal, until the app is force-killed and reopened.
Expected behavior
- A transient
kCLErrorLocationUnknownshould not permanently break location delivery — either filter it out (keep waiting, per Apple docs) or re-establish the subscription on the next request (e.g. resetlocationInitializedin the.catch, or model errors as values so the stream never terminates).
Real-world impact
Field app for construction workers: mandatory-GPS clock-in. Workers with the app open since morning got "no GPS" on every attempt for minutes and only succeeded after force-killing the app. We shipped a workaround (cap the plugin timeout, then fall back to WKWebView navigator.geolocation, which works fine in these "broken" sessions since it bypasses the plugin), but the plugin itself stays unusable after the first transient error.
Plugin version
@capacitor/geolocation: 8.2.0 (also affects 7.x by code inspection — same architecture since the IONGeolocationLib rewrite)- Capacitor: 8.4.1
- iOS (WKWebView,
server.urlremote)
Suggested fix
In bindLocationPublisher()'s .catch, reset locationInitialized = false (and drop locationCancellable) so the next request re-binds; or better, filter transient kCLErrorLocationUnknown in IONGLOCManagerWrapper.didFailWithError instead of nil-ing currentLocation, so the publisher never fails on a recoverable condition.
Activity
OS-pedrogustavobilro commentedon Aug 13, 2026
Hey @berlansk thanks for opening this issue. I believe this issue may have been fixed in #95, released in plugin version 8.2.1
Can you update the plugin version and check again?