I’m seeing a crash relating to
TaskGroup
, but unfortunately it’s only coming up in production and I have limited information on it (via Crashlytics). I’m guessing I’m abusing
TaskGroup
one way or another. Any advice as to where to start investigating an issue like this? Here’s the offending thread. I’ve tried at length to reproduce it locally but no luck.
Crashed: com.apple.root.user-initiated-qos.cooperative
EXC_BAD_ACCESS KERN_INVALID_ADDRESS 0x0000000000000040
Crashed: com.apple.root.user-initiated-qos.cooperative
0 libswift_Concurrency.dylib 0x31440 swift::TaskGroup::offer(swift::AsyncTask*, swift::AsyncContext*) + 504
1 libswift_Concurrency.dylib 0x2dc5c swift::AsyncTask::completeFuture(swift::AsyncContext*) + 132
2 libswift_Concurrency.dylib 0x2f4d0 completeTaskAndRelease(swift::AsyncContext*, swift::SwiftError*) + 128
3 libswift_Concurrency.dylib 0x2b0f0 swift::runJobInEstablishedExecutorContext(swift::Job*) + 132
4 libswift_Concurrency.dylib 0x2b9f8 swift_job_runImpl(swift::Job*, swift::ExecutorRef) + 72
5 libdispatch.dylib 0x1343c _dispatch_root_queue_drain + 340
6 libdispatch.dylib 0x13c38 _dispatch_worker_thread2 + 172
7 libsystem_pthread.dylib 0x4e48 _pthread_wqthread + 224
8 libsystem_pthread.dylib 0x49f0 start_wqthread + 8
I have only one use of TaskGroup in my project, and it seems pretty trivial.
// Function that processes a bunch of 'action triggers' and produces a stream of actions
func run(action: Action, find: @escaping (Model.Type) -> Model?) -> AsyncStream<Action> {
AsyncStream { continuation in
Task {
await withTaskGroup(of: Void.self) { group in
for trigger in triggers {
group.addTask {
for await result in trigger(action, find) {
if result is VoidAction { continue }
continuation.yield(result)
await group.waitForAll()
continuation.finish()
// Later, from an async context. Process an action and dispatch its output.
Task {
for await output in run(action: action, find: { store.find($0) }) {
try await store.dispatch(output)
Is there any way to dig into this without a more complete crash report?
Thanks for sharing your code. Hopefully someone more knowledgable than myself can reply. I was hitting a similar (but not the same) problem where my store.dispatch contained some Core Data related code that was not following proper managed object thread containment rules. (It mostly worked, except for sometimes.
)
A random thought I had. Is it okay for the different async child tasks to use the continuation variable concurrently? IOW, is continuation.yield re-enterant?
On which iOS version? I met similar crashes.
But after upgrading my device to latest iOS version,
the bug seems to be fixed.
I've also seen this crash. I can confirm it is reproducible on versions prior to 15.4 which is a blocker for adopting structured concurrency at my company.
I had hope Swift 5.6 would fix this issue. It seemingly did but a library responsible for the crash was for some reason not updated in Xcode 13.3 toolchain.
I got this failure on iOS 15.5 - could someone help check if it's the same error?
Crashed: com.apple.root.user-initiated-qos.cooperative
0 libswiftCore.dylib 0x39b74 assertionFailure(:_:file:line:flags:) + 308
1 libswift_Concurrency.dylib 0x5ed8 CheckedContinuation.resume(returning:) + 560
2 [AppName] 0x1fe0dc (1) await resume partial function for closure #2 in closure #2 in closure #1 in closure #1 in MsgRepo.fetchMsgs(storyId:updatedAfter:) + 4341768412 (:4341768412)
3 libswift_Concurrency.dylib 0x3b7cc swift::runJobInEstablishedExecutorContext(swift::Job*) + 244
4 libswift_Concurrency.dylib 0x3c1e8 swift_job_runImpl(swift::Job*, swift::ExecutorRef) + 72
5 libdispatch.dylib 0x15164 _dispatch_root_queue_drain + 396
6 libdispatch.dylib 0x1596c _dispatch_worker_thread2 + 164
7 libsystem_pthread.dylib 0x1080 _pthread_wqthread + 228
8 libsystem_pthread.dylib 0xe5c start_wqthread + 8
0 0x0000ffff8367aadc swift_task_cancel + 28 in libswift_Concurrency.so
1 0x0000ffff8367b508 swift_taskGroup_cancelAll + 47 in libswift_Concurrency.so
2 InfernoDevice.shutdown() + 551 in infernod at /build/inferno/control/InfernoAES70/Sources/InfernoDevice/Device.swift:490:27
489│ if let ocp1TaskGroup {
490│ ocp1TaskGroup.cancelAll()
│ ▲
491│ }