Non-Sendable passed across an actor boundary — walk the legitimate fixes and pick one
The call below fails to compile with "non-Sendable type 'UserProfile' passed across an actor boundary." List the legitimate fixes, then apply one.
Constraints:
- Do not silence the check with
@unchecked Sendable. - The store must stay an
actor; keep itssaveAPI.
final class UserProfile {
var name: String
var avatar: Data
init(name: String, avatar: Data) { self.name = name; self.avatar = avatar }
}
actor ProfileStore {
func save(_ profile: UserProfile) { /* persist */ }
}
func handoff(_ profile: UserProfile, to store: ProfileStore) async {
await store.save(profile) // error: UserProfile is not Sendable
}
Diagnose the cause and apply one fix.
Legitimate fixes — make the type Sendable (a value type or immutable final class); convert it to an actor; isolate both sides to @MainActor; or pass a sending value. Prefer a Sendable value model — it removes the hazard at its source.
- ✗Reaching for
@unchecked Sendableas the only fix - ✗Casting to
Anyto dodge the check - ✗Assuming a
Taskdeep-copies captured values across the boundary
- →When is converting the type to an
actorbetter than making itSendable? - →What does
sendingguarantee that plainSendabledoes not?
The cause is that UserProfile is a mutable, non-Sendable class, so it may not cross into the actor. The best fix is to make the model a Sendable value:
struct UserProfile: Sendable {
var name: String
var avatar: Data
}
actor ProfileStore {
func save(_ profile: UserProfile) { /* persist */ }
}
A value type of Sendable members copies safely across the boundary. Alternatives — turn UserProfile into an actor, isolate both sides to @MainActor, or pass a sending value; but the Sendable value removes the hazard at its source.