# \`sending\` cancellation handler in \`withTaskCancellationHandler\`

**URL:** <https://forums.swift.org/t/sending-cancellation-handler-in-withtaskcancellationhandler/87222>\
**Category:** Using Swift\
**Tags:** concurrency, swift, task, cancellation\
**Created:** [June 9, 2026, 4:10am UTC](https://forums.swift.org/t/sending-cancellation-handler-in-withtaskcancellationhandler/87222 "2026-06-09T04:10:51Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![soumyamahunt](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/soumyamahunt/32/23427_2.png) [@soumyamahunt](https://forums.swift.org/u/soumyamahunt)\
**Post date:** [June 9, 2026, 4:10am UTC](https://forums.swift.org/t/sending-cancellation-handler-in-withtaskcancellationhandler/87222/1 "2026-06-09T04:10:51Z")

</div>

In my use case I need to handle cancellation with [`withTaskCancellationHandler`](https://developer.apple.com/documentation/swift/withtaskcancellationhandler(operation:oncancel:isolation:)) that mutates a non-`Sendable` actor isolated value. The current API accepts the actor isolation input but only accepts `Sendable` cancellation handler. Is there any way to achieve this?

---

<div class="post-metadata">

**Author:** ![KeithBauerANZ](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/keithbaueranz/32/27897_2.png) [@KeithBauerANZ](https://forums.swift.org/u/KeithBauerANZ)\
**Post date:** [June 9, 2026, 4:22am UTC](https://forums.swift.org/t/sending-cancellation-handler-in-withtaskcancellationhandler/87222/2 "2026-06-09T04:22:38Z")

</div>

`unsafeBitCast` (I presume `withTaskCancellationHandler` can't actually call its handler more than once but maybe somebody can confirm that)

[`Disconnected<(() -> Void)?>`](https://forums.swift.org/t/pitch-disconnected-type-for-modeling-disconnected-values/86815). You can't consume the `Disconnected`, but you should be able to take the closure out of the Optional and call it.

`Mutex<(() -> Void)?>` as a slightly-inefficient `Disconnected`.

---

<div class="post-metadata">

**Author:** ![FranzBusch](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/franzbusch/32/19447_2.png) [@FranzBusch](https://forums.swift.org/u/FranzBusch)\
**Post date:** [June 9, 2026, 2:21pm UTC](https://forums.swift.org/t/sending-cancellation-handler-in-withtaskcancellationhandler/87222/3 "2026-06-09T14:21:16Z")

</div>

Cancellation handlers can and will be called from arbitrary contexts depending on where the task is cancelled from. The handler can definitely be `sending` instead of `@Sendable` since they are guaranteed to be called once. However, accessing actor isolated state isn't easily possible inside them since that requires an `async` context. Two ways to make this work:

1. Protect the state with a `Mutex` instead of an actor which will allow you to access the state through the `Mutex`.
2. Spawn an unstructured task that dispatches the access to the actor

I would normally recommend against the second approach since I recommend reducing the usage of unstructured tasks but it might be the easier approach that doesn't require a larger refactoring.

---

<div class="post-metadata">

**Author:** ![soumyamahunt](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/soumyamahunt/32/23427_2.png) [@soumyamahunt](https://forums.swift.org/u/soumyamahunt)\
**Post date:** [June 10, 2026, 3:47am UTC](https://forums.swift.org/t/sending-cancellation-handler-in-withtaskcancellationhandler/87222/4 "2026-06-10T03:47:52Z")

</div>

> [@FranzBusch](#):
>
> Cancellation handlers can and will be called from arbitrary contexts depending on where the task is cancelled from. The handler can definitely be `sending` instead of `@Sendable` since they are guaranteed to be called once. However, accessing actor isolated state isn't easily possible inside them since that requires an `async` context. Two ways to make this work:

The linked doc mentions that cancellation closure is isolated to the passed actor, is the doc incorrect here? I agree the signature API signature doesn't match what the doc mentions, mainly cancellation handler should be `sending isolated(any)`.

---

<div class="post-metadata">

**Author:** ![vanvoorden](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/vanvoorden/32/33619_2.png) [@vanvoorden](https://forums.swift.org/u/vanvoorden)\
**Post date:** [June 10, 2026, 3:56am UTC](https://forums.swift.org/t/sending-cancellation-handler-in-withtaskcancellationhandler/87222/5 "2026-06-10T03:56:12Z")

</div>

> [@soumyamahunt](#):
>
> The linked doc mentions that cancellation closure is isolated to the passed actor, is the doc incorrect here?

I had a similar question before. Here might be some more clues:

> [@Sendable Closures that are also isolated and synchronous?](https://forums.swift.org/t/sendable-closures-that-are-also-isolated-and-synchronous/85156/11):
>
> In this sample: func isMainThread() -\> Bool { return Thread.isMainThread } let task = Task.detached { await withTaskCancellationHandler( operation: { @MainActor in print("operation() started -\> isMainActor: \(isMainThread()), thread: \(pthread\_self())") try? await Task.sleep(for: .seconds(2)) print("operation() finished -\> isMainActor: \(isMainThread()), thread: \(pthread\_self())") }, onCancel: { print("onCancel()…

---

<div class="post-metadata">

**Author:** ![soumyamahunt](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/soumyamahunt/32/23427_2.png) [@soumyamahunt](https://forums.swift.org/u/soumyamahunt)\
**Post date:** [June 10, 2026, 4:05am UTC](https://forums.swift.org/t/sending-cancellation-handler-in-withtaskcancellationhandler/87222/6 "2026-06-10T04:05:16Z")

</div>

Thanks for linking this thread @vanvoorden, the doc is wrong here (no surprise there for an Apple doc 😅 ).

---

<div class="post-metadata">

**Author:** ![ktoso](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/ktoso/32/44526_2.png) [@ktoso](https://forums.swift.org/u/ktoso)\
**Post date:** [June 10, 2026, 8:34am UTC](https://forums.swift.org/t/sending-cancellation-handler-in-withtaskcancellationhandler/87222/7 "2026-06-10T08:34:42Z")

</div>

Heh, a lot of the documentation wording in that page explains exactly the right semantics; I see there's one incorrect sentence, [I've fixed it now](https://github.com/swiftlang/swift/pull/89826).

Please call out mistakes, open issues, or even PRs to fix these things. There's a lot of folks editing things and sometimes things slip through -- thanks in advance.
