Summary
App terminates with EXC_BREAKPOINT (SIGTRAP) triggered by swift_unexpectedError
during (very likely) a HealthKit query invocation. Reproduced on two devices
(iPhone 15, iPhone 17), affects at least library versions consumed in our builds
across multiple weeks — the crash signature has been stable.
swift_unexpectedError indicates a Swift async task threw an Error that
wasn't declared/awaited as throws in the caller chain, so the runtime traps.
No custom Swift code in our app — the only Swift-based native module in our
stack is @kingstinct/react-native-healthkit.
Environment
@kingstinct/react-native-healthkit: 14.0.2 (npm latest)
- React Native: 0.81.x
- Expo SDK 54
- Nitro Modules: 0.35.x
- iOS: 26.5.2 (23F84)
- Devices: iPhone 15 (
iPhone15,4), iPhone 17 (iPhone18,3)
- Architecture: arm64 / arm64e
- Distribution: TestFlight
Trigger
User action that reliably precedes the crash:
- Pull-to-refresh on a screen that runs a HealthKit-import flow, OR
- Explicit "Import from Apple Health" button.
Both entry points funnel into the same code path which calls, per workout:
queryWorkoutSamples({ filter: { date: { startDate, strictStartDate: true } }, limit: 0, ascending: true })
followed for each returned WorkoutProxy by:
workout.getWorkoutRoutes() // HKWorkoutRoute
queryStatisticsForQuantity('HKQuantityTypeIdentifierHeartRate', ['discreteAverage','discreteMax'], { from, to, unit: 'count/min' })
queryStatisticsForQuantity('HKQuantityTypeIdentifierBasalEnergyBurned', ['cumulativeSum'], { from, to, unit: 'kcal' })
App uptime at crash: ~100 seconds — consistent with the auto-import kicking off
during app-start plus a user-triggered second import.
Crash Log (Thread 3, crashed)
Exception Type: EXC_BREAKPOINT (SIGTRAP)
Exception Codes: 0x0000000000000001, 0x0000000184cc3800
Termination Reason: SIGNAL 5 Trace/BPT trap: 5
Triggered by Thread: 3
Thread 3 Crashed:
0 libswiftCore.dylib assertionFailure(:_:file:line:flags:) + 168 AssertCommon.swift:171
1 libswiftCore.dylib swift_unexpectedError + 688 ErrorType.swift:216
2 libswift_Concurrency.dylib swift::runJobInEstablishedExecutorContext(Job*) Actor.cpp:243
3 libswift_Concurrency.dylib swift_job_runImpl(Job*, SerialExecutorRef) Actor.cpp:2222
4 libdispatch.dylib _dispatch_root_queue_drain + 360 queue.c:7473
5 libdispatch.dylib _dispatch_worker_thread2 + 184 queue.c:7551
6 libsystem_pthread.dylib _pthread_wqthread + 232
7 libsystem_pthread.dylib start_wqthread + 8
Full .crash files (2 different devices, same signature) available on request.
Suspected cause
An async throws function inside the Swift module is invoked from a Task { ... }
(or a Task.detached { ... }) whose closure isn't declared to propagate the error.
When a specific workout hits an edge case in the query pipeline (permission
denied for a subtype, missing route metadata, or an invalid HKQuantityStatistic
option combination), the throw hits swift_unexpectedError and the process is
terminated.
Common pattern that produces exactly this stack:
Task { // <- no `Task<Void, Error>`, no do/catch
try await someHealthKitCall() // throws → swift_unexpectedError → crash
}
Reproduction environment
- Real device, no simulator.
- User has ~30 days of Apple Health workouts imported prior.
- Trigger the import path multiple times in short succession (auto-import at
app start + manual pull-to-refresh 30-90s later).
- On our end this hits reliably enough that we have multiple TestFlight
crashlogs across weeks with identical signature.
Ask
- Is there a known place in the Swift wrapper where an
async throw could
escape without a surrounding Task error handler? Especially in the
workout-route or per-workout statistics paths.
- Any interim workaround (call ordering, option adjustments, or a way to
detect the offending workout) appreciated. Happy to run instrumented
builds or share more detailed logs.
Thanks for maintaining this library — it's otherwise been rock solid for us.
Summary
App terminates with
EXC_BREAKPOINT (SIGTRAP)triggered byswift_unexpectedErrorduring (very likely) a HealthKit query invocation. Reproduced on two devices
(iPhone 15, iPhone 17), affects at least library versions consumed in our builds
across multiple weeks — the crash signature has been stable.
swift_unexpectedErrorindicates a Swiftasynctask threw anErrorthatwasn't declared/awaited as
throwsin the caller chain, so the runtime traps.No custom Swift code in our app — the only Swift-based native module in our
stack is
@kingstinct/react-native-healthkit.Environment
@kingstinct/react-native-healthkit: 14.0.2 (npmlatest)iPhone15,4), iPhone 17 (iPhone18,3)Trigger
User action that reliably precedes the crash:
Both entry points funnel into the same code path which calls, per workout:
followed for each returned
WorkoutProxyby:App uptime at crash: ~100 seconds — consistent with the auto-import kicking off
during app-start plus a user-triggered second import.
Crash Log (Thread 3, crashed)
Exception Type: EXC_BREAKPOINT (SIGTRAP)
Exception Codes: 0x0000000000000001, 0x0000000184cc3800
Termination Reason: SIGNAL 5 Trace/BPT trap: 5
Triggered by Thread: 3
Thread 3 Crashed:
0 libswiftCore.dylib assertionFailure(:_:file:line:flags:) + 168 AssertCommon.swift:171
1 libswiftCore.dylib swift_unexpectedError + 688 ErrorType.swift:216
2 libswift_Concurrency.dylib swift::runJobInEstablishedExecutorContext(Job*) Actor.cpp:243
3 libswift_Concurrency.dylib swift_job_runImpl(Job*, SerialExecutorRef) Actor.cpp:2222
4 libdispatch.dylib _dispatch_root_queue_drain + 360 queue.c:7473
5 libdispatch.dylib _dispatch_worker_thread2 + 184 queue.c:7551
6 libsystem_pthread.dylib _pthread_wqthread + 232
7 libsystem_pthread.dylib start_wqthread + 8
Full
.crashfiles (2 different devices, same signature) available on request.Suspected cause
An
async throwsfunction inside the Swift module is invoked from aTask { ... }(or a
Task.detached { ... }) whose closure isn't declared to propagate the error.When a specific workout hits an edge case in the query pipeline (permission
denied for a subtype, missing route metadata, or an invalid HKQuantityStatistic
option combination), the throw hits
swift_unexpectedErrorand the process isterminated.
Common pattern that produces exactly this stack:
Reproduction environment
app start + manual pull-to-refresh 30-90s later).
crashlogs across weeks with identical signature.
Ask
asyncthrow couldescape without a surrounding
Taskerror handler? Especially in theworkout-route or per-workout statistics paths.
detect the offending workout) appreciated. Happy to run instrumented
builds or share more detailed logs.
Thanks for maintaining this library — it's otherwise been rock solid for us.