AVPlayer.replaceCurrentItem(with:) "Incorrect actor executor assumption" runtime crash when building for iOS 18

Hi there,

I have some code that's been working fine for the last few versions of iOS and macOS and all the others, and now causes a runtime crash in iOS 18/macOS 15 etc.

I have an actor called Player which is basically a big wrapper around an AVPlayer. It all gets compiled down to a Framework, and my clients use it by dropping it in to their video player app code. It handles everything needed for them to be able to talk to our media infrastructure and handles telemetry.

It has its own property called avplayer which is an AVPlayer. Gets created at the init().

It has a function called load(_ avPlayerItem: AVPlayerItem) which the clients use to load a new video into player.

The offending code (which used to work!) looks like this:

Task { @MainActor in
    avplayer.replaceCurrentItem(with: avPlayerItem)
}

No warnings in Xcode. When you run it, it crashes on iOS 18 and macOS 15 with this error in the debugger:

Incorrect actor executor assumption

I thought, "Okay well maybe replaceCurrentItem has changed and doesn't need to be on the main actor anymore, so even if you say this outside of a Main Actor-scoped task:

avplayer.replaceCurrentItem(with: avPlayerItem)

...it still crashes the exact same way.

Does anyone have any ideas? I'm under some heavy pressure here to get this working and I don't even know where to start with this.

Big thanks in advance.

Thankfully for a "quick fix" the only thing I had to do was set the Swift language version back to 5, and the error is gone. So, no more emergency :)

Still would love to know what is going on though!

Hello @Suges,

Could you provide a link to a project that reproduces the issue?

I tried reproducing based on your description but was unsuccessful.

Best regards,

Greg

Hi Greg,

Yes I've been trying to crate a "pared-down" version to submit a ticket but I can't seem to trigger it. There must be something else in my code that's changing the actor's context somehow?

I'm going to keep adding more and more chunks of code from the original version to the pared-down version until I trigger it, then update here.

Thanks!

I think what’s happened here is some bad architecture on my part that the compiler didn’t catch, really.

My Player actor uses another actor called TelemetryManager to do all the telemetry things. I didn't mention it before because I didn't think it was related!

In order for it to do that, it needs to have access to Player's AVPlayer because it observes AVPlayer’s property publishers and also reads AVPlayer’s properties when it’s about to send telemetry.

So (simplifying the code) in Player you have:

let player = AVPlyer()
lazy var telemetryManager = TelemetryManager(player: player)

Even TelemetryManager itself hands off tracking the state of the media being played to yet another actor called VideoStateTracker which also gets passed this AVPlayer.

So somewhere along the line with all this passing around of AVPlayer the actor executor is being changed or shadowed or something. If I don't attach TelemetryManager at all to Player, everything runs fine.

This taught me to stop passing AVPlayer around and:

  1. Have Player do all property observing itself and call functions on TelemetryManager when something it would want to know about happens
  2. Do "constructor injection" instead of passing AVPlayer, i.e. when TelemetryManager is about to fire off a report and needs the current state of AVPlayer, it calls an injected function from Player to get a snapshot of AVPlayer's current state

...and now it all works great!

AVPlayer.replaceCurrentItem(with:) "Incorrect actor executor assumption" runtime crash when building for iOS 18
 
 
Q