# Actor \`assumeIsolated\` erroneously crashes when using a dispatch queue as the underlying executor

**URL:** <https://forums.swift.org/t/actor-assumeisolated-erroneously-crashes-when-using-a-dispatch-queue-as-the-underlying-executor/72434>\
**Category:** Using Swift\
**Tags:** dispatchqueue, assumeisolated, actor, serialexecutor\
**Created:** [June 13, 2024, 2:25am UTC](https://forums.swift.org/t/actor-assumeisolated-erroneously-crashes-when-using-a-dispatch-queue-as-the-underlying-executor/72434 "2024-06-13T02:25:17Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![wadetregaskis](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/wadetregaskis/32/8494_2.png) [@wadetregaskis](https://forums.swift.org/u/wadetregaskis)\
**Post date:** [June 13, 2024, 2:25am UTC](https://forums.swift.org/t/actor-assumeisolated-erroneously-crashes-when-using-a-dispatch-queue-as-the-underlying-executor/72434/1 "2024-06-13T02:25:17Z")

</div>

```swift
import Dispatch

actor Example {
    final class DispatchQueueExecutor: SerialExecutor {
        private let queue: DispatchQueue

        init(queue: DispatchQueue) {
            self.queue = queue
        }

        func enqueue(_ job: UnownedJob) {
            self.queue.async {
                job.runSynchronously(on: self.asUnownedSerialExecutor())
            }
        }

        func asUnownedSerialExecutor() -> UnownedSerialExecutor {
            UnownedSerialExecutor(ordinary: self)
        }
    }

    private let executor: DispatchQueueExecutor

    init(queue: DispatchQueue) {
        self.executor = DispatchQueueExecutor(queue: queue)
    }

    func bridge() {
        print("Sadly, I never get my moment.")
    }

    nonisolated var unownedExecutor: UnownedSerialExecutor {
        executor.asUnownedSerialExecutor()
    }
}

let queue = DispatchQueue(label: "Example")
let example = Example(queue: queue)

queue.sync {
    example.assumeIsolated {
        $0.bridge()
    }
}

```

> Fatal error: Incorrect actor executor assumption; Expected same executor as Example.

`lldb` confirms that it _is_ in fact running in the correct Dispatch queue when `assumeIsolated` is invoked (and that, if I instead spawn up an intermediary `Task` and await into the actor that way, that the actor _is_ using the given Dispatch queue for its execution).

Implementing `isSameExclusiveExecutionContext` makes no difference (whether or not I change it to use `UnownedSerialExecutor(complexEquality:)`).

This seems like it can only be a bug?

Is there a workaround, to allow me to efficiently (and _synchronously_) invoke the actor's methods from inside the Dispatch queue?

I'm using Swift 6 (swiftlang-6.0.0.3.300 clang-1600.0.20.10).

---

<div class="post-metadata">

**Author:** ![dehesa](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/dehesa/32/10911_2.png) [@dehesa](https://forums.swift.org/u/dehesa)\
**Post date:** [August 9, 2024, 3:49pm UTC](https://forums.swift.org/t/actor-assumeisolated-erroneously-crashes-when-using-a-dispatch-queue-as-the-underlying-executor/72434/2 "2024-08-09T15:49:24Z")

</div>

Just got to the same crash today. As far as I understand from @ktoso [pitch](https://forums.swift.org/t/pitch-custom-isolation-checking-for-serialexecutor/69786) and its subsequent [proposal](https://github.com/swiftlang/swift-evolution/blob/main/proposals/0424-custom-isolation-checking-for-serialexecutor.md), this issue will be solved by implementing `checkIsolated()`. However that function seems to only be used by runtimes from macOS 15+. Is this right @ktoso ? Any way to use `assumeIsolated(_:)` in OSes lower than 15?

My current executor looks similar to @wadetregaskis with slight differences since I need to support macOS 14:

```swift
public import Dispatch

public extension DispatchQueue {
  final class Executor: SerialExecutor {
    public let queue: DispatchQueue

    public init(label: ReverseDNS, qos: DispatchQoS, autoreleaseFrequency: AutoreleaseFrequency = .inherit) {
      self.queue = DispatchQueue(label: label.rawValue, qos: qos, attributes: [], autoreleaseFrequency: autoreleaseFrequency, target: nil)
    }
  }
}

public extension DispatchQueue.Executor {
  @inlinable func enqueue(_ job: consuming ExecutorJob) {
    let unownedJob = UnownedJob(consume job)
    let unownedSerialExecutor = self.asUnownedSerialExecutor()

    #if compiler(>=6.0)
    if #available(macOS 15, *) {
      let unownedTaskExecutor = self.asUnownedTaskExecutor()
      return queue.async {
        unownedJob.runSynchronously(isolatedTo: unownedSerialExecutor, taskExecutor: unownedTaskExecutor)
      }
    }
    #else
    queue.async {
      unownedJob.runSynchronously(on: unownedSerialExecutor)
    }
    #endif
  }

  @inlinable func asUnownedSerialExecutor() -> UnownedSerialExecutor {
    UnownedSerialExecutor(ordinary: self)
  }
}

#if compiler(>=6.0)
@available(macOS 15, *)
extension DispatchQueue.Executor: TaskExecutor {
  @inlinable public func asUnownedTaskExecutor() -> UnownedTaskExecutor {
    UnownedTaskExecutor(ordinary: self)
  }

  @inlinable public func checkIsolated() {
    dispatchPrecondition(condition: .onQueue(queue))
  }
}
#endif

```

Is there any way to backdeploy `TaskExecutor`s as well?

---

<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:** [August 10, 2024, 1:00pm UTC](https://forums.swift.org/t/actor-assumeisolated-erroneously-crashes-when-using-a-dispatch-queue-as-the-underlying-executor/72434/3 "2024-08-10T13:00:39Z")

</div>

There’s no way to backdeploy this feature without significant effort and tbh I don’t even know if possible at all. So, no.

---

<div class="post-metadata">

**Author:** ![Karl](https://avatars.discourse-cdn.com/v4/letter/k/34f0e0/32.png) [@Karl](https://forums.swift.org/u/Karl)\
**Post date:** [August 12, 2024, 4:31pm UTC](https://forums.swift.org/t/actor-assumeisolated-erroneously-crashes-when-using-a-dispatch-queue-as-the-underlying-executor/72434/4 "2024-08-12T16:31:04Z")

</div>

You can kind of hack around it:

```swift
actor Foo {

    let queue = DispatchSerialQueue(label: "My Foo")

    nonisolated var unownedExecutor: UnownedSerialExecutor {
        queue.asUnownedSerialExecutor()
    }

    private nonisolated func assumeIsolatedHack<T>(
        _ block: (isolated Foo) throws -> T
    ) rethrows -> T where T: Sendable {

        // Before Swift 6, dispatch didn't work well with `Actor.assumeIsolated`.
        // It can report false negatives - where you are actually on the correct queue but 'assumeIsolated'
        // doesn't know it. That was fixed in SE-0424:
        // https://github.com/swiftlang/swift-evolution/blob/main/proposals/0424-custom-isolation-checking-for-serialexecutor.md
        //
        // This feature requires a new version of the Swift runtime, so we need to perform an OS version check
        // and on older systems we need an ugly hack to emulate the new 'assumeIsolated' for Dispatch.

        if #available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, *) {
            return try self.assumeIsolated(block)
        } else {
            dispatchPrecondition(condition: .onQueue(self.queue))
            return try withoutActuallyEscaping(block) {
                let isolationStripped = unsafeBitCast($0, to: ((Foo) throws -> T).self)
                return try isolationStripped(self)
            }
        }
    }
}

```

Then you can use actors for Obj-C delegates who always get messages posted on the queue you configure them with.

---

<div class="post-metadata">

**Author:** ![dehesa](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/dehesa/32/10911_2.png) [@dehesa](https://forums.swift.org/u/dehesa)\
**Post date:** [August 13, 2024, 8:50am UTC](https://forums.swift.org/t/actor-assumeisolated-erroneously-crashes-when-using-a-dispatch-queue-as-the-underlying-executor/72434/5 "2024-08-13T08:50:06Z")

</div>

I was aware of the `assumeIsolatedHack(_:)`. In my codebase, I have it as an extension from `Actor` called `unsafeIsolated(_:)`. However, this produces the following warning in Xcode 16 betas for macOS 14 (and lower):

```swift
warning: data race detected: actor-isolated function at MyFile.swift:N was not called on the same actor

```

The problem is not the warning per se, which I can simply ignore (although it doesn't look good). The problem is that (if my understanding is correct from reading the evolution proposals), the Swift runtime dynamically tracks the current executor of a running task in thread local storage. Meaning that dispatching something directly to the queue doesn't forward the actor info. You can easily replicate by running the following test in macOS 14, Xcode 16 and using my previous `DispatchQueue.Executor` helper.

```swift
actor CustomActor {
  let executor = DispatchQueue.Executor(label: "myQueue", qos: .default)

  @inlinable nonisolated var unownedExecutor: UnownedSerialExecutor {
    executor.asUnownedSerialExecutor()
  }
}

```

```swift
internal import XCTest

final class FileSystemTests: XCTestCase {
  func testWarning() async throws {
    let actor = CustomActor()
    actor.executor.queue.async {
      // Entering this closure will produce a warning (and not forward actor info)
      actor.unsafeIsolated { _ in
        print("This has been unsafely isolated")
      }

      // Entering this closure will crash your program
      actor.assumeIsolated { _ in
        print("This has been assumed isolated")
      }
    }
    try await Task.sleep(for: .seconds(1))
  }
}

```

@ktoso, is there any way for me to unsafely forward the actor information for the "unsafely isolated" context?

---

<div class="post-metadata">

**Author:** ![Karl](https://avatars.discourse-cdn.com/v4/letter/k/34f0e0/32.png) [@Karl](https://forums.swift.org/u/Karl)\
**Post date:** [August 13, 2024, 9:54am UTC](https://forums.swift.org/t/actor-assumeisolated-erroneously-crashes-when-using-a-dispatch-queue-as-the-underlying-executor/72434/6 "2024-08-13T09:54:11Z")

</div>

> [@dehesa](#):
>
> However, this produces the following warning in Xcode 16 betas for macOS 14 (and lower):
> 
> ```swift
> warning: data race detected: actor-isolated function at MyFile.swift:N was not called on the same actor
> 
> ```
> 
> The problem is not the warning per se, which I can simply ignore (although it doesn't look good).

I wonder if Xcode should really be enabling that warning if it produces different results on macOS 14 vs 15.

> [@dehesa](#):
>
> is there any way for me to unsafely forward the actor information for the "unsafely isolated" context?

Yeah this would be good. I think the current situation could really use some adjustment prior to 6.0 final, if that's still possible.

Users will try to isolate data using actors and dispatch queues, which in theory is compatible with the Apple SDK practice of registering delegate objects and queues to call them on. Because delegate methods have to be callable from Objective-C with their existing signatures, they have to be formally `nonisolated` and we dynamically check isolation using `assertIsolated` in the body. This is not _too_ difficult to grasp and not an extremely uncommon use-case, I don't think.

So developers will do that, test their code on iOS 18 or macOS 15, and everything will work. Then they'll ship it and it'll crash for customers on older OSes. It won't make intuitive sense, and they won't be able to reproduce it until they notice that it's OS version-dependent. Even when they do, they'll see in the debugger that they're on the correct queue, but `assumeIsolated` is giving an unexpected result, and I bet a lot of them will blame themselves and feel that they just don't understand Swift Concurrency.

Even if they get past that hurdle and identify `assumeIsolated` as the culprit, there's no good answer right now for what they should do about it. There's the `unsafeBitCast` trick I used, but it's a very valid point that some of the runtime bookkeeping may be in an unexpected state because of that. But if that is no longer an option, I don't think developers will have any choice but to forgo actors with dispatch executors for these use-cases entirely until they can drop support for all but the not-even-released-yet round of Apple OS releases.

If it is truly not feasible to back-port the current behaviour, an `unsafeAssumeIsolated` method to replace the `unsafeBitCast` (and update the runtime bookkeeping) should be looked at as a high-priority addition, IMO. We could combine that with our own versions of the executor 'complex equality' checks to effectively write our own back-ports for the executors we use.

---

<div class="post-metadata">

**Author:** ![dehesa](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/dehesa/32/10911_2.png) [@dehesa](https://forums.swift.org/u/dehesa)\
**Post date:** [August 13, 2024, 10:12am UTC](https://forums.swift.org/t/actor-assumeisolated-erroneously-crashes-when-using-a-dispatch-queue-as-the-underlying-executor/72434/7 "2024-08-13T10:12:29Z")

</div>

> [@Karl](#):
>
> I wonder if Xcode should really be enabling that warning if it produces different results on macOS 14 vs 15.

I think the warning is correct and should be kept. The runtime is detecting no actor information and it is letting us know. It is a pity that Xcode 15 doesn't have this behavior as well, though.

> [@Karl](#):
>
> So developers will do that, test their code on iOS 18 or macOS 15, and everything will work. Then they'll ship it and it'll crash for customers on older OSes. It won't make intuitive sense, and they won't be able to reproduce it until they notice that it's OS version-dependent.

That is a very good point that I didn't foresee. I can easily imagine people wasting hours/days trying to figure this out.

> [@Karl](#):
>
> If it is truly not feasible to back-port the current behaviour, an `unsafeAssumeIsolated` method to replace the `unsafeBitCast` (and update the runtime bookkeeping) should be looked at as a high-priority addition, IMO.

Agreed!

---

<div class="post-metadata">

**Author:** ![Karl](https://avatars.discourse-cdn.com/v4/letter/k/34f0e0/32.png) [@Karl](https://forums.swift.org/u/Karl)\
**Post date:** [August 13, 2024, 10:50am UTC](https://forums.swift.org/t/actor-assumeisolated-erroneously-crashes-when-using-a-dispatch-queue-as-the-underlying-executor/72434/8 "2024-08-13T10:50:33Z")

</div>

> [@dehesa](#):
>
> The problem is that (if my understanding is correct from reading the evolution proposals), the Swift runtime dynamically tracks the current executor of a running task in thread local storage

Looking at the runtime implementation, even the new `assumeIsolated` behaviour doesn't seem to actually _set_ anything. And actually, I recall from when these functions were proposed it was very clear that the runtime won't use this information to make scheduling decisions.

So the `unsafeBitCast` trick seems safe to me.

(And since this is only for when we run on an existing OS, we don't need to worry that the runtime code might change. When we run on a newer OS, we won't need to do any of this)

Still, it's not great that developers will encounter this issue at all, and I still think it's worth packaging up the `unsafeBitCast` thing for them in a back-deployed API so they can at least work around the issue with a bit more peace of mind (and some documentation reminding them to check for isolation manually).

---

<div class="post-metadata">

**Author:** ![dehesa](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/dehesa/32/10911_2.png) [@dehesa](https://forums.swift.org/u/dehesa)\
**Post date:** [August 13, 2024, 12:39pm UTC](https://forums.swift.org/t/actor-assumeisolated-erroneously-crashes-when-using-a-dispatch-queue-as-the-underlying-executor/72434/9 "2024-08-13T12:39:50Z")

</div>

Could you send me some links to where in the Swift codebase that is defined, please?

---

<div class="post-metadata">

**Author:** ![Karl](https://avatars.discourse-cdn.com/v4/letter/k/34f0e0/32.png) [@Karl](https://forums.swift.org/u/Karl)\
**Post date:** [August 13, 2024, 2:26pm UTC](https://forums.swift.org/t/actor-assumeisolated-erroneously-crashes-when-using-a-dispatch-queue-as-the-underlying-executor/72434/10 "2024-08-13T14:26:36Z")

</div>

`assumeIsolated` checks the executor using `_taskIsCurrentExecutor`, and if that returns true, it actually does an `unsafeBitCast` itself.

> <https://github.com/swiftlang/swift/blob/2941f24da32c10fe0b51685f54e8694ccc3e884c/stdlib/public/Concurrency/ExecutorAssertions.swift#L348>

That hasn't changed recently. It's been doing exactly that [since at least Swift 5.9](https://github.com/swiftlang/swift/blob/9067148bc9c9a72730dbeebef32965b3aaeb34fb/stdlib/public/Concurrency/ExecutorAssertions.swift#L232).

You wouldn't expect `_taskIsCurrentExecutor` to modify any current executor bookkeeping, but we can take a look at its implementation just to be sure:

> <https://github.com/swiftlang/swift/blob/2941f24da32c10fe0b51685f54e8694ccc3e884c/stdlib/public/Concurrency/Actor.cpp#L405>

Abbreviating, here's the part we care about:

```cpp
if (!current) {
    // We have no current executor, i.e. we are running "outside" of Swift
    // Concurrency. We could still be running on a thread/queue owned by
    // the expected executor however, so we need to try a bit harder before
    // we fail.

   <snip>

    // We cannot use 'complexEquality' as it requires two executor instances,
    // and we do not have a 'current' executor here.

    // Otherwise, as last resort, let the expected executor check using
    // external means, as it may "know" this thread is managed by it etc.
    if (isCurrentExecutorMode == Swift6_UseCheckIsolated_AllowCrash) {
      swift_task_checkIsolated(expectedExecutor); // will crash if not same context

      // checkIsolated did not crash, so we are on the right executor, after all!
      return true;
    }

```

`swift_task_checkIsolated` just calls in to your protocol witness - so if your implementation says the isolation is correct, `_taskIsCurrentExecutor` returns true, and `assumeIsolated` performs the bit-cast. No modifying of runtime-internal data AFAICT.

The [5.9 implementation](https://github.com/swiftlang/swift/blob/9067148bc9c9a72730dbeebef32965b3aaeb34fb/stdlib/public/Concurrency/Actor.cpp#L308) didn't modify anything, either. The difference is quite clear - when we don't have a current executor tracked, the old implementation had one hard-coded check for the main thread but lacks the new `checkIsolated` fallback. But it had its own same-executor hook (requires 2 executors, so unsuitable for this problem) and it worked basically the same way.

@ktoso can say for sure, but to me it looks like a plain unsafe bit-cast is sufficient as a back-deployable fallback.

---

<div class="post-metadata">

**Author:** ![dehesa](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/dehesa/32/10911_2.png) [@dehesa](https://forums.swift.org/u/dehesa)\
**Post date:** [August 14, 2024, 2:40pm UTC](https://forums.swift.org/t/actor-assumeisolated-erroneously-crashes-when-using-a-dispatch-queue-as-the-underlying-executor/72434/11 "2024-08-14T14:40:00Z")

</div>

Thank you for taking the time spelunking in swiftlang codebase and pointing out the targeted places, @Karl . I've learned a lot and your analysis seems correct to me. I'd love to hear a bit more input from @ktoso if possible.

---

<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:** [August 16, 2024, 5:11am UTC](https://forums.swift.org/t/actor-assumeisolated-erroneously-crashes-when-using-a-dispatch-queue-as-the-underlying-executor/72434/12 "2024-08-16T05:11:32Z")

</div>

If you know for sure both actors are on a specific dispatch queue, you can write the `dispatchPrecondition` yourself -- this is what DispatchSerialQueue does inside its `checkIsolation` and do the cast.

Please be VERY careful with this and only do the unsafe cast trick when you're ABSOLUTELY sure (right after the dispatchPrecondition and you're sure that all involved queues are the same due to that).

Note that it's impossible to write an API like "am I on the right dispatch queue -\> true/false", all APIs will either return true or _crash_. Even ones in Dispatch which look like they would return false never will. (There's some ancient hidden APIs there you might find, but they will never return false)

---

<div class="post-metadata">

**Author:** ![dehesa](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/dehesa/32/10911_2.png) [@dehesa](https://forums.swift.org/u/dehesa)\
**Post date:** [August 16, 2024, 7:36am UTC](https://forums.swift.org/t/actor-assumeisolated-erroneously-crashes-when-using-a-dispatch-queue-as-the-underlying-executor/72434/13 "2024-08-16T07:36:32Z")

</div>

The problem is that `checkIsolation()` is only called if you are running in macOS 15+. If I have an actor with a custom executor implementing `checkIsolation()` running in macOS 14, the program will crash.

See the example I added some post above:

> [@dehesa](#):
>
> ```swift
> actor CustomActor {
> let executor = DispatchQueue.Executor(label: "myQueue", qos: .default)
> 
> @inlinable nonisolated var unownedExecutor: UnownedSerialExecutor {
> executor.asUnownedSerialExecutor()
> }
> }
> 
> ```
> 
> ```swift
> internal import XCTest
> 
> final class FileSystemTests: XCTestCase {
> func testWarning() async throws {
> let actor = CustomActor()
> actor.executor.queue.async {
> // Entering this closure will produce a warning (and not forward actor info)
> actor.unsafeIsolated { _ in
> print("This has been unsafely isolated")
> }
> 
> // Entering this closure will crash your program
> actor.assumeIsolated { _ in
> print("This has been assumed isolated")
> }
> }
> try await Task.sleep(for: .seconds(1))
> }
> }
> 
> ```

---

<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:** [August 16, 2024, 7:39am UTC](https://forums.swift.org/t/actor-assumeisolated-erroneously-crashes-when-using-a-dispatch-queue-as-the-underlying-executor/72434/14 "2024-08-16T07:39:10Z")

</div>

Well, yeah. I'm not sure if that's a reply to my post or to what? Yes, this feature requires the new runtime and building against new SDK as we said earlier.

I was confirming the "horrible cast" can be done if you are _absolutely certain the isolation is correct due to some other means/checks_, because `checkIsolated` is only a recent OS feature -- that's why I mention manually calling dispatchPrecondition and then casting.

---

<div class="post-metadata">

**Author:** ![dehesa](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/dehesa/32/10911_2.png) [@dehesa](https://forums.swift.org/u/dehesa)\
**Post date:** [August 16, 2024, 7:55am UTC](https://forums.swift.org/t/actor-assumeisolated-erroneously-crashes-when-using-a-dispatch-queue-as-the-underlying-executor/72434/15 "2024-08-16T07:55:59Z")

</div>

There might have been a bit of a misunderstanding. First, thank you for taking the time to answer. I do appreciate it.

To establish some common points:

- We are aware of the existence of `dispatchPrecondition`.
- We are aware that there are no APIs to check whether "we are on the right dispatch queue".
- We are aware of "unsafe cast" and that we must be absolutely certain before using it (casting in general should never be done if possible).
- We are aware that `checkIsolated` is only a recent OS feature and it seems to be impossible to backdeploy.

The topic of this whole post was to figure out why `assumeIsolated` was crashing with custom executors, and once that we figured that out, is to see whether there is any way to jump from a `DispatchQueue` to an actor in macOS 14- without "asyncing it" (i.e. using `Task`) and without producing a warning every single time we use the unsafe casting (e.g. my `unsafeIsolated(_:)` function).

---

<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:** [August 16, 2024, 8:02am UTC](https://forums.swift.org/t/actor-assumeisolated-erroneously-crashes-when-using-a-dispatch-queue-as-the-underlying-executor/72434/16 "2024-08-16T08:02:23Z")

</div>

Ok this helps understand the question. So you're asking about the _runtime_ warning, this was a bit hidden in all those messages here tbh and I missed it 🙂

That's a runtime warning that is gone in Swift 6 (well, in Concurrency library shipping in those OSes that contain Swift 6+), so in before Swift 6 which you care about here... I believe you can disable it with the env var `SWIFT_UNEXPECTED_EXECUTOR_LOG_LEVEL=0`:

Here's some notes about it:

```swift
/// Logging level for unexpected executors:
/// 0 - no logging -- will be IGNORED when Swift6 mode of isCurrentExecutor is used
/// 1 - warn on each instance -- will be IGNORED when Swift6 mode of isCurrentExecutor is used
/// 2 - fatal error
///
/// NOTE: The default behavior on Apple platforms depends on the SDK version
/// an application was linked to. Since Swift 6 the default is to crash,
/// and the logging behavior is no longer available.

```

It's worth documenting some more perhaps in the migration guide, would you mind filing an issue about it or contributing a section? [GitHub - apple/swift-migration-guide](https://github.com/apple/swift-migration-guide)

* * *

All this is a very "have the cake and eat it too" situation to be honest. The entire reason this warning happens is because the "old" runtime cannot detect the queues properly - because as you now know, there's no APIs to do so.

The fix for this detecting is `checkIsolated` basically and turning off the runtime warning into strict checks which are entirely correct.

In other words, the same functionality that was powering the warning is what we've improved in 6.0, so if you're going to do 6.0 `assume...` style APIs, the previous runtime just has no idea about how that's correct and to the best of its knowledge is warning you about it.

For development I think it's fine to try to disable that logging mode, but be super careful with the assumptions, and then try to move to 6.0 runtimes as soon as you can.

---

<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:** [August 16, 2024, 8:09am UTC](https://forums.swift.org/t/actor-assumeisolated-erroneously-crashes-when-using-a-dispatch-queue-as-the-underlying-executor/72434/17 "2024-08-16T08:09:08Z")

</div>

Separately, it seems that env variable wasn't done in the "more modern" way we can do them and it would not have shown up on `SWIFT_DEBUG_HELP=y swift` invocations... I'll fix this separately so at least it is documented in the command line output: [SWIFT\_UNEXPECTED\_EXECUTOR\_LOG\_LEVEL should be declared in EnvironmentVariables.def · Issue #75921 · swiftlang/swift · GitHub](https://github.com/swiftlang/swift/issues/75921)

---

<div class="post-metadata">

**Author:** ![dehesa](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/dehesa/32/10911_2.png) [@dehesa](https://forums.swift.org/u/dehesa)\
**Post date:** [August 16, 2024, 8:37am UTC](https://forums.swift.org/t/actor-assumeisolated-erroneously-crashes-when-using-a-dispatch-queue-as-the-underlying-executor/72434/18 "2024-08-16T08:37:32Z")

</div>

> [@ktoso](#):
>
> I believe you can disable it with the env var `SWIFT_UNEXPECTED_EXECUTOR_LOG_LEVEL=0`

I wasn't aware of the existence of this. Thank you. If I understand correctly this will be project-wide (or at least SPM module-wide), which I am uneasy setting since there are more developers working in the codebase with "less concurrency knowledge". I can always make a very small target/module with the custom executor code, I guess.

> [@ktoso](#):
>
> For development I think it's fine to try to disable that logging mode, but be super careful with the assumptions, and then try to move to 6.0 runtimes as soon as you can.

I would love to just upgrade the requirements and force users to only use the Swift 6.0 runtime (i.e. macOS 15+). We would have mass-riots if we do that 🙃

> [@ktoso](#):
>
> The fix for this detecting is `checkIsolated` basically and turning off the runtime warning into strict checks which are entirely correct.
> 
> In other words, the same functionality that was powering the warning is what we've improved in 6.0, so if you're going to do 6.0 `assume`... style APIs, the previous runtime just has no idea about how that's correct and to the best of its knowledge is warning you about it.

Yeah, I understand and applaud the new development 😄 It is great and I can't wait to use it. Sadly, it seems, it will be quite some years before we can use `checkIsolated`.

---

<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:** [August 16, 2024, 8:46am UTC](https://forums.swift.org/t/actor-assumeisolated-erroneously-crashes-when-using-a-dispatch-queue-as-the-underlying-executor/72434/19 "2024-08-16T08:46:08Z")

</div>

> [@dehesa](#):
>
> I wasn't aware of the existence of this. Thank you. If I understand correctly this will be project-wide (or at least SPM module-wide), which I am uneasy setting since there are more developers working in the codebase with "less concurrency knowledge". I can always make a very small target/module with the custom executor code, I guess.

It's an environment variable, so entire _process_ wide.

---

<div class="post-metadata">

**Author:** ![dehesa](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/dehesa/32/10911_2.png) [@dehesa](https://forums.swift.org/u/dehesa)\
**Post date:** [August 16, 2024, 9:03am UTC](https://forums.swift.org/t/actor-assumeisolated-erroneously-crashes-when-using-a-dispatch-queue-as-the-underlying-executor/72434/20 "2024-08-16T09:03:53Z")

</div>

> [@ktoso](#):
>
> It's worth documenting some more perhaps in the migration guide, would you mind filing an issue about it or contributing a section?

I left an issue [here](https://github.com/apple/swift-migration-guide/issues/136).

[Next page](https://forums.swift.org/t/actor-assumeisolated-erroneously-crashes-when-using-a-dispatch-queue-as-the-underlying-executor/72434.md?page=2)
