# Feedback wanted: confusing concurrency diagnostic messages

**URL:** <https://forums.swift.org/t/feedback-wanted-confusing-concurrency-diagnostic-messages/72523>\
**Category:** Compiler\
**Tags:** concurrency\
**Created:** [June 16, 2024, 4:43pm UTC](https://forums.swift.org/t/feedback-wanted-confusing-concurrency-diagnostic-messages/72523 "2024-06-16T16:43:31Z")\
**Posts on this page:** 20\
**Page:** 2

<div class="post-metadata">

**Author:** ![Michael\_Gottesman](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/michael_gottesman/32/280_2.png) [@Michael\_Gottesman](https://forums.swift.org/u/Michael_Gottesman)\
**Post date:** [June 25, 2024, 6:57pm UTC](https://forums.swift.org/t/feedback-wanted-confusing-concurrency-diagnostic-messages/72523/21 "2024-06-25T18:57:58Z")

</div>

This is actually already on my radar. We did a pass over of the main diagnostics some time ago, but I did not do "sending" since we were still figuring out the final name. I am going to be doing another pass over specifically the sending diagnostics soon. But thank you for the report! I appreciate it = ).

---

<div class="post-metadata">

**Author:** ![mattie](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/mattie/32/13267_2.png) [@mattie](https://forums.swift.org/u/mattie)\
**Post date:** [June 26, 2024, 8:13pm UTC](https://forums.swift.org/t/feedback-wanted-confusing-concurrency-diagnostic-messages/72523/22 "2024-06-26T20:13:23Z")

</div>

Very minor, but I've now found a case where the compiler does the opposite of what was decided on in another issue related to "nonisolated" vs "non-isolated".

> <https://github.com/swiftlang/swift/issues/74749>
>
> \### Description
> 
> Per https://github.com/swiftlang/swift/issues/73982, the compil…er seems to have standarized on using the spelling "nonisolated" in prose. However, here's an example where "non-isolated" is used.
> 
> \`\`\`
> test.swift:4:5: error: main actor-isolated var 'global' can not be mutated from a non-isolated context
> 1 | var global = 42
> | \`- note: mutation of this var is only permitted within the actor
> 2 | 
> 3 | func mutate() {
> | \`- note: add '@MainActor' to make global function 'mutate()' part of global actor 'MainActor'
> 4 | global += 1
> | \`- error: main actor-isolated var 'global' can not be mutated from a non-isolated context
> 5 | }
> 6 | 
> \`\`\`
> 
> \### Reproduction
> 
> \`\`\`swift
> var global = 42
> 
> func mutate() {
> global += 1
> }
> \`\`\`
> 
> 
> \### Expected behavior
> 
> "nonisolated" should be used everywhere
> 
> \### Environment
> 
> Apple Swift version 6.0-dev (LLVM 5b37bd4c1c578e9, Swift 54898ce105c7185)
> Target: arm64-apple-macosx14.0
> 
> \### Additional information
> 
> \_No response\_

I also discovered differences in how the suggestion to add a global actor annotation is made.

> <https://github.com/swiftlang/swift/issues/74751>
>
> \### Motivation
> 
> I found two situations that are recommending the same thing, but… in different ways.
> 
> input 1:
> 
> \`\`\`swift
> var global = 42
> \`\`\`
> 
> diagnostics 1:
> 
> \`\`\`
> test.swift:1:5: error: var 'global' is not concurrency-safe because it is non-isolated global shared mutable state
> 1 | var global = 42
> | |- error: var 'global' is not concurrency-safe because it is non-isolated global shared mutable state
> | |- note: convert 'global' to a 'let' constant to make 'Sendable' shared state immutable
> | |- note: annotate 'global' with '@MainActor' if property should only be accessed from the main actor
> | \`- note: disable concurrency-safety checks if accesses are protected by an external synchronization mechanism
> 2 | 
> \`\`\`
> 
> Highlight:
> 
> \`note: annotate 'global' with '@MainActor' if property should only be accessed from the main actor\`
> 
> input 2:
> 
> \`\`\`swift
> var global = 42
> 
> func mutate() {
> global += 1
> }
> \`\`\`
> 
> diagnostics 2:
> 
> \`\`\`
> test.swift:4:5: error: main actor-isolated var 'global' can not be mutated from a non-isolated context
> 1 | var global = 42
> | \`- note: mutation of this var is only permitted within the actor
> 2 | 
> 3 | func mutate() {
> | \`- note: add '@MainActor' to make global function 'mutate()' part of global actor 'MainActor'
> 4 | global += 1
> | \`- error: main actor-isolated var 'global' can not be mutated from a non-isolated context
> 5 | }
> 6 | 
> \`\`\`
> 
> highlight: \`note: add '@MainActor' to make global function 'mutate()' part of global actor 'MainActor'\`
> 
> \### Proposed solution
> 
> I think the second note seems like its more general-purpose. But, I think including "annotate" does help.
> 
> \`note: annotate 'global' with '@MainActor' if property should only be accessed from the main actor\`
> 
> could become:
> 
> \`note: add '@MainActor' annotation to make property 'global' part of global actor 'MainActor'\`
> 
> 
> \### Alternatives considered
> 
> \_No response\_
> 
> \### Additional information
> 
> \_No response\_

---

<div class="post-metadata">

**Author:** ![Vinicius\_Vendramini](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/vinicius_vendramini/32/12370_2.png) [@Vinicius\_Vendramini](https://forums.swift.org/u/Vinicius_Vendramini)\
**Post date:** [July 3, 2024, 7:42pm UTC](https://forums.swift.org/t/feedback-wanted-confusing-concurrency-diagnostic-messages/72523/23 "2024-07-03T19:42:09Z")

</div>

I got a bit confused the other day in this code snippet:

```swift
let standardError = Pipe()
var error = ""
var errorStream = Data()

let standardErrorQueue: OperationQueue = createStandardErrorQueue()
standardErrorQueue.addOperation(BlockOperation(block: {
	while handleInput(pipe: standardError, stream: &errorStream, result: &error) {}
}))

```

It was in the middle of a `static func`, and gave me the errors `Mutation of captured var 'error' in concurrently-executed code` and `Mutation of captured var 'errorStream' in concurrently-executed code`.

I think I understand how this might create a race condition, though I don't think it does (the rest of the code is very straightforward). I haven't yet studied actors and sendable etc to know what would be an ideal way to rewrite this, and for now I just wanted the code to compile so I could fix other (more important) stuff, so after some trial and error I added `nonisolated(unsafe)` to the variable declarations and the error disappeared.

I thought It'd be worth mentioning because the error didn't really direct me towards either an ideal solution or an "unsafe fix". I only thought about adding `nonisolated(unsafe)` after a while, and even then it was only because this had worked to fix other errors that suggested that annotation as a fix-it.

* * *

Edit: here's the link to the full code, in case it's useful: [Gryphon/Sources/GryphonLib/Shell.swift at 89cc51358a8858865e05d98a9d734c209e6eb035 · vinivendra/Gryphon · GitHub](https://github.com/vinivendra/Gryphon/blob/89cc51358a8858865e05d98a9d734c209e6eb035/Sources/GryphonLib/Shell.swift#L100)

---

<div class="post-metadata">

**Author:** ![twof](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/twof/32/1628_2.png) [@twof](https://forums.swift.org/u/twof)\
**Post date:** [July 11, 2024, 7:47am UTC](https://forums.swift.org/t/feedback-wanted-confusing-concurrency-diagnostic-messages/72523/24 "2024-07-11T07:47:49Z")

</div>

I was helping a friend who was new to Swift with a project earlier today and ran into this.

```swift
@MainActor
struct Foo {
  func baz() { }
}

func bar() {
  let foo = Foo()
  foo.baz()
}

```

For this we get the following error description and fixit

```swift
Call to main actor-isolated instance method 'baz()' in a synchronous nonisolated context

INFO: Calls to instance method 'baz()' from outside of its actor context are implicitly asynchronous

FIXIT: Add '@MainActor' to make global function 'bar()' part of global actor 'MainActor'

```

The person I was mentoring had trouble understanding what was happening and what they did wrong. We started out by accepting the fixit in order to get compiling code, and then planned to come back and talk about why this change was needed or not needed. This resulted in a cascade of errors where adding `@MainActor` to one function required that they also accept fixits in several other places.

Some suggestions:

- While it might not be possible to have specific error messages for arbitrary actors, I expect that new users of Swift will likely first run into this error in relation to `@MainActor`, so altering the error message to be less jargon-heavy when `@MainActor` is involved might allow for a more gentle onboarding.
- A potential rewording of the error message could be `baz is isolated to the main actor by @MainActor, but the calling function is not and could be executed by any actor. Function calls that are not explicitly isolated to the same actor as their parent must be preformed asynchronously.`
- Two fixits could be suggested here. Either isolate `bar` with `@MainActor`, or make `bar` async and prepend the call to `baz` with `await`.
- A note may be justified here to alert the user of the hazards of isolating their function to the main actor since it's potentially a mistake if the function also contains CPU intensive work.
- The wording of `make global function 'bar()' part of global actor 'MainActor'` feels wrong to me. It's difficult to understand what it means for a function to be "part of" an actor. Would it also be accurate to say `@MainActor` causes the function to be run on MainActor or executed by MainActor? Either of those feel more approachable to me.
- Nit, and probably out of scope for this discussion, but specifying that a function is an instance method/global function feels overly wordy to me, and in my opinion is not particularly useful. Same thing with "global actor".

In the end after talking through my mentee what it meant to annotate a function with `@MainActor`, we annotated only the function that needed it (it had a call to a 3rd party lib that required it), and made the calling functions do so asynchronously.

---

<div class="post-metadata">

**Author:** ![twof](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/twof/32/1628_2.png) [@twof](https://forums.swift.org/u/twof)\
**Post date:** [July 13, 2024, 4:22am UTC](https://forums.swift.org/t/feedback-wanted-confusing-concurrency-diagnostic-messages/72523/25 "2024-07-13T04:22:39Z")

</div>

```swift
protocol NodeProtocol: Actor { }
struct PrintNode: NodeProtocol { } // Error: Non-class type 'PrintNode' cannot conform to class protocol 'Actor'

```

This error message is incorrect since the protocol is not a class protocol and making `PrintNode` a class will not fix the issue. When we switch `PrintNode` to a class, we get the correct error message.

```swift
// Non-actor type 'PrintNode' cannot conform to the 'Actor' protocol

```

We also get a fixit to switch `PrintNode` to an actor, which we should probably also get when `PrintNode` is a struct. Changing the type from value to reference semantics is a little iffy though, so I can understand why you might not want to do that.

---

<div class="post-metadata">

**Author:** ![Fritzt](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/fritzt/32/16046_2.png) [@Fritzt](https://forums.swift.org/u/Fritzt)\
**Post date:** [July 31, 2024, 8:45am UTC](https://forums.swift.org/t/feedback-wanted-confusing-concurrency-diagnostic-messages/72523/26 "2024-07-31T08:45:25Z")

</div>

The following Swift-6 error (Xcode 16 beta 4) is hard to understand and the steps to resolve the error unclear:

`error: cannot form key path to main actor-isolated property 'xyz'`

See the following thread for an example:

[key path error](https://forums.swift.org/t/swift-6-compiler-bug-or-human-error/73591)

---

<div class="post-metadata">

**Author:** ![tomhamming](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/tomhamming/32/12153_2.png) [@tomhamming](https://forums.swift.org/u/tomhamming)\
**Post date:** [August 12, 2024, 5:38pm UTC](https://forums.swift.org/t/feedback-wanted-confusing-concurrency-diagnostic-messages/72523/27 "2024-08-12T17:38:03Z")

</div>

Here's one that doesn't make very clear what the underlying problem is:

> [@How do I solve "task-isolated value...passed as strongly transferred parameter" warning?](https://forums.swift.org/t/how-do-i-solve-task-isolated-value-passed-as-strongly-transferred-parameter-warning/73870):
>
> I'm in Xcode 16 beta 5. I've got this code: @objc class func fetch(product: StoreListProduct, completion: @escaping @Sendable (AppStoreProduct?) -\> Void) { Task { let result = await AppStoreProduct.product(forListProduct: product) DispatchQueue.main.async { completion(result) } } } For context: I am moving to StoreKit 2 in a largely Objective-C codebase. StoreListProduct is an Objective-C class that wraps an NSDictionary …

---

<div class="post-metadata">

**Author:** ![hassila](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/hassila/32/22647_2.png) [@hassila](https://forums.swift.org/u/hassila)\
**Post date:** [August 26, 2024, 1:30pm UTC](https://forums.swift.org/t/feedback-wanted-confusing-concurrency-diagnostic-messages/72523/28 "2024-08-26T13:30:38Z")

</div>

Here is one:  
`'AnyActor' is deprecated: Use 'any Actor' with 'DistributedActor.asLocalActor' instead`

```swift
public protocol OrdoObjectListPlugin: AnyActor {
...
}

```

No fix-it, the intention is to constrain the protocol to actors - not sure how I am expected to constrain the protocol with the information provided?

---

<div class="post-metadata">

**Author:** ![hborla](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/hborla/32/27563_2.png) [@hborla](https://forums.swift.org/u/hborla)\
**Post date:** [August 26, 2024, 4:28pm UTC](https://forums.swift.org/t/feedback-wanted-confusing-concurrency-diagnostic-messages/72523/29 "2024-08-26T16:28:12Z")

</div>

> [@hassila](#):
>
> the intention is to constrain the protocol to actors - not sure how I am expected to constrain the protocol with the information provided?

If you're just trying to constrain to actors, you should refine `Actor`. Are you trying to constrain conformances to either actors or distributor actors?

---

<div class="post-metadata">

**Author:** ![hassila](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/hassila/32/22647_2.png) [@hassila](https://forums.swift.org/u/hassila)\
**Post date:** [August 27, 2024, 9:05am UTC](https://forums.swift.org/t/feedback-wanted-confusing-concurrency-diagnostic-messages/72523/30 "2024-08-27T09:05:35Z")

</div>

Thanks Holly,

Just constraining to Actor is what I wanted in this case - must admit I think that constraint was just assumed to be analogous to constraining to AnyObject and it "worked" for 5.10, so got confused by the error message... Thanks!

---

<div class="post-metadata">

**Author:** ![mattie](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/mattie/32/13267_2.png) [@mattie](https://forums.swift.org/u/mattie)\
**Post date:** [October 16, 2024, 1:46pm UTC](https://forums.swift.org/t/feedback-wanted-confusing-concurrency-diagnostic-messages/72523/31 "2024-10-16T13:46:14Z")

</div>

Here's one. I think there's quite a bit of redundant information the note. But, a little rewording and some links to help find the relevent definitions could help a lot.

> <https://github.com/swiftlang/swift/issues/77048>
>
> \### Motivation
> 
> Given this code, we get an error.
> 
> \`\`\`swift
> class MyClass {
> …	func doStuff() async {
> }
> }
> 
> @MainActor
> class UseClass {
> let value = MyClass()
> 
> func useClass() async {
> await value.doStuff()
> }
> }
> \`\`\`
> 
> \`\`\`
> error: sending 'self.value' risks causing data races
> note: sending main actor-isolated 'self.value' to nonisolated instance method 'doStuff()' risks causing data races between nonisolated and main actor-isolated uses
> \`\`\`
> 
> That note is quite long and I think some of the information is redundant. The first bit clarifies the differnece in isolation. That's good!
> 
> \`sending main actor-isolated 'self.value' to nonisolated instance method 'doStuff()'\`
> 
> The second bit is re-stating the error:
> 
> \`risks causing data races\`
> 
> And then the third part is really just re-stating the difference in isolation again
> 
> \`between nonisolated and main actor-isolated uses\`
> 
> Maybe we can do better?
> 
> \### Proposed solution
> 
> I'm just making stuff up quickly, but how about something like this:
> 
> \`\`\`
> error: sending 'self.value' risks causing data races
> note: calling the nonisolated instance method 'doStuff()' requires that main actor-isolated 'self.value' cross an isolation boundary \<Link to variable definition\>
> note: \<Type\> does not conform to \`Sendable\` \<Link to Type definition\>
> \`\`\`
> 
> \### Alternatives considered
> 
> \_No response\_
> 
> \### Additional information
> 
> \_No response\_

---

<div class="post-metadata">

**Author:** ![PoshAlpaca](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/poshalpaca/32/21519_2.png) [@PoshAlpaca](https://forums.swift.org/u/PoshAlpaca)\
**Post date:** [October 25, 2024, 11:50am UTC](https://forums.swift.org/t/feedback-wanted-confusing-concurrency-diagnostic-messages/72523/32 "2024-10-25T11:50:24Z")

</div>

Here's one that recently left me confused until I realized what my mistake was:

```swift
let values = AsyncStream { 0 }

for value in values { // Error: For-in loop requires 'AsyncStream<Int>' to conform to 'Sequence'
  print(value)
}

```

The solution of course is to use `for await`. Maybe the compiler could hint at this when it sees you're trying to use a normal for-loop for an async sequence.

---

<div class="post-metadata">

**Author:** ![bjhomer](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/bjhomer/32/313_2.png) [@bjhomer](https://forums.swift.org/u/bjhomer)\
**Post date:** [December 4, 2024, 9:53pm UTC](https://forums.swift.org/t/feedback-wanted-confusing-concurrency-diagnostic-messages/72523/33 "2024-12-04T21:53:33Z")

</div>

I ran across this error message today:

> Value of non-Sendable type '@isolated(any) @async @callee\_guaranteed @substituted \<τ\_0\_0\> () -\> @out τ\_0\_0 for ' accessed after being transferred; later accesses could race

```swift
class NonSendable {}

func test() async {
    await withTaskGroup(of: Bool.self) { group in
        for ns in [NonSendable()] {
            // 🛑: Value of non-Sendable type '@isolated(any)
            // @async @callee_guaranteed @substituted <τ_0_0> () 
            // -> @out τ_0_0 for <Bool>' accessed after being 
            // transferred; later accesses could race.
            group.addTask {
                print(ns)
                return false
            }
        }
        await group.waitForAll()
    }
}

```

I suspect most developers (including myself) don't know what a `@isolated(any) @async @callee_guaranteed @substituted <τ_0_0> () -> @out τ_0_0 for <Bool>` is.

The actual problem here seems to be that I'm capturing a non-sendable type, but the diagnostic message didn't lead me in that direction!

---

<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:** [December 4, 2024, 10:27pm UTC](https://forums.swift.org/t/feedback-wanted-confusing-concurrency-diagnostic-messages/72523/34 "2024-12-04T22:27:55Z")

</div>

Oh yeah, I have an even worse variant of that:

> Lock.swift:225:31: warning: returning a task-isolated '@noescape @callee\_guaranteed @substituted \<τ\_0\_0, τ\_0\_1, τ\_0\_2, τ\_0\_3\> (UnsafeMutablePointer\<τ\_0\_0\>, UnsafeMutablePointer\<τ\_0\_1\>) -\> (@out τ\_0\_3, @error\_indirect τ\_0\_2) for \<os\_unfair\_lock\_s, State, E, R\>' value as a 'sending' result risks causing data races; this is an error in the Swift 6 language mode  
> return try lockBuffer.withUnsafeMutablePointers(unsafeWithLockPointers)  
> ^  
> Lock.swift:225:31: note: returning a task-isolated '@noescape @callee\_guaranteed @substituted \<τ\_0\_0, τ\_0\_1, τ\_0\_2, τ\_0\_3\> (UnsafeMutablePointer\<τ\_0\_0\>, UnsafeMutablePointer\<τ\_0\_1\>) -\> (@out τ\_0\_3, @error\_indirect τ\_0\_2) for \<os\_unfair\_lock\_s, State, E, R\>' value risks causing races since the caller assumes the value can be safely sent to other isolation domains  
> return try lockBuffer.withUnsafeMutablePointers(unsafeWithLockPointers)  
> ^  
> Lock.swift:225:31: note: '@noescape @callee\_guaranteed @substituted \<τ\_0\_0, τ\_0\_1, τ\_0\_2, τ\_0\_3\> (UnsafeMutablePointer\<τ\_0\_0\>, UnsafeMutablePointer\<τ\_0\_1\>) -\> (@out τ\_0\_3, @error\_indirect τ\_0\_2) for \<os\_unfair\_lock\_s, State, E, R\>' is a non-Sendable type  
> return try lockBuffer.withUnsafeMutablePointers(unsafeWithLockPointers)

Then there's this one that came up in another forum thread the other day:

[![](https://global.discourse-cdn.com/swift/original/3X/7/8/7805867070a40548ac6813160c01ac2b2862514b.png) ](https://global.discourse-cdn.com/swift/original/3X/7/8/7805867070a40548ac6813160c01ac2b2862514b.png)

---

<div class="post-metadata">

**Author:** ![Jumhyn](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/jumhyn/32/3891_2.png) [@Jumhyn](https://forums.swift.org/u/Jumhyn)\
**Post date:** [December 11, 2024, 7:51pm UTC](https://forums.swift.org/t/feedback-wanted-confusing-concurrency-diagnostic-messages/72523/35 "2024-12-11T19:51:21Z")

</div>

Not a compile-time diagnostic but I think falls squarely in this realm: [App crashes from compiler added hidden assert](https://forums.swift.org/t/app-crashes-from-compiler-added-hidden-assert/76548)

---

<div class="post-metadata">

**Author:** ![Jon\_Shier](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/jon_shier/32/921_2.png) [@Jon\_Shier](https://forums.swift.org/u/Jon_Shier)\
**Post date:** [December 20, 2024, 9:47pm UTC](https://forums.swift.org/t/feedback-wanted-confusing-concurrency-diagnostic-messages/72523/36 "2024-12-20T21:47:11Z")

</div>

This has likely been posted, but I wanted to bring up this case again, from the [AoC](https://forums.swift.org/t/advent-of-code-2024/76301/129) thread.

 ![0bbfd0491d7840131210d7f73e32eaaa94a39096_2_1380x220](https://global.discourse-cdn.com/swift/original/3X/3/0/30c5aba6a67b9abbb419c294ec73feb56abd1432.png)

This error is especially confusing because it points to the closure being passed to `addTask` and not to the actual cause of the issue. While the closure type may technically be the cause of the issue, it's really caused by the closure type inference failing due to the code inside the closure. Is there any way the compiler can distinguish inferred types, especially for closures, and look at what cause the inference to return a different type than required? It could even be special cased to just closure parameters, as the closure itself doesn't usually feel like part of the code the user provides but something that the IDE/compiler/API gave us to fill in. Especially in Swift where the syntax is simply `{}`. Even something as simply as the compiler silently compiling a version of the closure as if it had an explicit return type that matched the parameter type (in this case `{ () async -> Int in }`), which usually get the compiler to return the true errors.

---

<div class="post-metadata">

**Author:** ![BlueSparrow](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/bluesparrow/32/38500_2.png) [@BlueSparrow](https://forums.swift.org/u/BlueSparrow)\
**Post date:** [December 20, 2024, 10:12pm UTC](https://forums.swift.org/t/feedback-wanted-confusing-concurrency-diagnostic-messages/72523/37 "2024-12-20T22:12:16Z")

</div>

Thanks for posting, Jon. I did stick my head in this thread and I saw some similar messages earlier, so I wasn't sure if it was valuable to add it here or not.

[The code in question](https://github.com/bhelyer/AOC2024/blob/0e124eebae63cf7421ffeb42f3f3f4b4b5fd69a2/Sources/Programs/Day20.swift). Just change line 29 to assign a mutable copy of grid instead to trigger the error.

---

<div class="post-metadata">

**Author:** ![ole](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/ole/32/18720_2.png) [@ole](https://forums.swift.org/u/ole)\
**Post date:** [January 1, 2025, 2:22pm UTC](https://forums.swift.org/t/feedback-wanted-confusing-concurrency-diagnostic-messages/72523/38 "2025-01-01T14:22:27Z")

</div>

I find the compiler error "Task or actor isolated value cannot be sent" (discussed e.g. in this thread: [Task or actor isolated value cannot be sent](https://forums.swift.org/t/task-or-actor-isolated-value-cannot-be-sent/76879/1)) confusing for grammar reasons.

I'm not a native English speaker, but I think this diagnostic should be as follows (note the added hyphens), to make clear that the task itself is not the problem:

"Task- or actor-isolated value cannot be sent"

or alternatively:

"Task-isolated or actor-isolated value cannot be sent"

It would be even better if the name of the variable that is being sent could be named in the diagnostic, e.g.:

"Task- or actor-isolated value 'myVar' cannot be sent"

It's sometimes not immediately clear to me which variable this is talking about. For example, [this post from the thread mentioned above](https://forums.swift.org/t/task-or-actor-isolated-value-cannot-be-sent/76879/6) shows a screenshot where the diagnostic is attached rather generically to a `Task` closure rather than a specific expression in the closure body (perhaps because the isolated value in question in this case is the implicit 'self'?). If the closure body were longer than just a single expression, it would not be immediately apparent to which expression the diagnostic is referring.

---

<div class="post-metadata">

**Author:** ![Jon\_Shier](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/jon_shier/32/921_2.png) [@Jon\_Shier](https://forums.swift.org/u/Jon_Shier)\
**Post date:** [January 1, 2025, 6:22pm UTC](https://forums.swift.org/t/feedback-wanted-confusing-concurrency-diagnostic-messages/72523/39 "2025-01-01T18:22:35Z")

</div>

Unless there's a type of isolation not mentioned, I'm not sure the `Task or actor` part even helps. Ideally the diagnostic would include all the relevant info in the message itself.

- "Main-actor isolated value `myVar` cannot be sent, as it is not otherwise `Sendable`."
- "Default executor isolated value `myVar` cannot be sent, as there is a local mutable reference."
- "Task-local value `myVar` cannot be sent..."

Unfortunately Swift seems to prefer messages which include little contextual information, instead relying on the code position information to inform users, which is itself often incorrect. Simple messages likely make creating and maintaining them easier, but we miss out on critical information.

---

<div class="post-metadata">

**Author:** ![Michael\_Gottesman](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/michael_gottesman/32/280_2.png) [@Michael\_Gottesman](https://forums.swift.org/u/Michael_Gottesman)\
**Post date:** [January 2, 2025, 8:43pm UTC](https://forums.swift.org/t/feedback-wanted-confusing-concurrency-diagnostic-messages/72523/40 "2025-01-02T20:43:43Z")

</div>

> [@Jon\_Shier](#):
>
> This has likely been posted, but I wanted to bring up this case again, from the [AoC](https://forums.swift.org/t/advent-of-code-2024/76301/129) thread.
> 
> ![0bbfd0491d7840131210d7f73e32eaaa94a39096_2_1380x220](https://global.discourse-cdn.com/swift/original/3X/3/0/30c5aba6a67b9abbb419c294ec73feb56abd1432.png)
> 
> This error is especially confusing because it points to the closure being passed to `addTask` and not to the actual cause of the issue. While the closure type may technically be the cause of the issue, it's really caused by the closure type inference failing due to the code inside the closure. Is there any way the compiler can distinguish inferred types, especially for closures, and look at what cause the inference to return a different type than required? It could even be special cased to just closure parameters, as the closure itself doesn't usually feel like part of the code the user provides but something that the IDE/compiler/API gave us to fill in. Especially in Swift where the syntax is simply `{}`. Even something as simply as the compiler silently compiling a version of the closure as if it had an explicit return type that matched the parameter type (in this case `{ () async -> Int in }`), which usually get the compiler to return the true errors.

That is not actually what is happening. What is most likely happening is that the closure is capturing some sort of main actor isolated state, causing the closure itself to also be main actor isolated. It does not have anything to do with the type system.

That being said, this has been already improved on main. Look at the following example:

```swift
class NS {}

@MainActor
class C {
  let ns = NS()

  func test() async {
    let x = ns
    await withTaskGroup { group in
      group.addTask {
        print(x)
      }
    }
  }
}

```

Now we emit the following error:

```swift
test.swift:12:21: error: passing closure as a 'sending' parameter risks causing data races between main actor-isolated code and concurrent execution of the closure
10 | let x = ns
11 | await withTaskGroup { group in
12 | group.addTask {
   | `- error: passing closure as a 'sending' parameter risks causing data races between main actor-isolated code and concurrent execution of the closure
13 | print(x)
   | `- note: closure captures 'x' which is accessible to main actor-isolated code
14 | }
15 | }

```

notice how it points out the error as the closure... but it also is able to point out that the reason for the error is that the closure captures 'x' which is part of the main actor since it was bound to the value of 'ns' earlier in the function.

[Previous page](https://forums.swift.org/t/feedback-wanted-confusing-concurrency-diagnostic-messages/72523.md?page=1)

[Next page](https://forums.swift.org/t/feedback-wanted-confusing-concurrency-diagnostic-messages/72523.md?page=3)
