zed-industries/zed · error
RealtimeAudio priority should use spawn_realtime, not dispat
Error message
RealtimeAudio priority should use spawn_realtime, not dispatch
What it means
The Windows dispatcher maps GPUI task priorities onto Windows thread-pool callback priorities, and RealtimeAudio is deliberately excluded: real-time audio tasks must go to the dedicated real-time path via spawn_realtime so they get the audio thread and its priority handling. If any code routes a RealtimeAudio-priority runnable through the generic dispatch(), the dispatcher panics immediately to surface the API misuse.
Source
Thrown at crates/gpui_windows/src/dispatcher.rs:109
#[inline(always)]
pub(crate) fn execute_runnable(runnable: RunnableVariant) {
let location = runnable.metadata().location;
let spawned = runnable.metadata().spawned;
gpui::profiler::update_running_task(spawned, location);
runnable.run();
gpui::profiler::save_task_timing();
}
}
impl PlatformDispatcher for WindowsDispatcher {
fn is_main_thread(&self) -> bool {
current().id() == self.main_thread_id
}
fn dispatch(&self, runnable: RunnableVariant, priority: Priority) {
let priority = match priority {
Priority::RealtimeAudio => {
panic!("RealtimeAudio priority should use spawn_realtime, not dispatch")
}
Priority::High => TP_CALLBACK_PRIORITY_HIGH,
Priority::Medium => TP_CALLBACK_PRIORITY_NORMAL,
Priority::Low => TP_CALLBACK_PRIORITY_LOW,
};
self.dispatch_on_threadpool(priority, runnable);
}
fn dispatch_on_main_thread(&self, runnable: RunnableVariant, priority: Priority) {
match self.main_sender.send(priority, runnable) {
Ok(_) => {
if !self.wake_posted.swap(true, Ordering::AcqRel) {
unsafe {
PostMessageW(
Some(self.platform_window_handle.as_raw()),
WM_GPUI_TASK_DISPATCHED_ON_MAIN_THREAD,
WPARAM(self.validation_number),
LPARAM(0),View on GitHub (pinned to f4178619ac)
Solutions
- Route real-time audio tasks through spawn_realtime (e.g. background_executor().spawn_realtime(...)) instead of spawn/dispatch with Priority::RealtimeAudio
- If you cannot use spawn_realtime in that context, downgrade the priority to High so the generic dispatch path is legal
- Audit call sites for tasks configured with RealtimeAudio that are handed to generic dispatch/spawn APIs
- Check the gpui changelog/docs: the dispatch vs spawn_realtime split is a hard contract on Windows
Example fix
// before: panics on Windows - RealtimeAudio reaches generic dispatch let task = TaskBuilder::new(audio_work).priority(Priority::RealtimeAudio); cx.background_executor().dispatch(task); // ends in WindowsDispatcher::dispatch // after: use the dedicated real-time spawn path let task = TaskBuilder::new(audio_work).priority(Priority::RealtimeAudio); cx.background_executor().spawn_realtime(task);
Defensive patterns
Strategy: validation
Validate before calling
// single scheduling helper that enforces the dispatch/spawn_realtime split
fn schedule(executor: &BackgroundExecutor, priority: Priority, task: Task) {
if matches!(priority, Priority::RealtimeAudio) {
executor.spawn_realtime(task);
} else {
executor.spawn(task);
}
} Type guard
fn needs_realtime_pool(priority: Priority) -> bool {
matches!(priority, Priority::RealtimeAudio)
} Prevention
- Treat RealtimeAudio as spawn_realtime-only by convention and encode it in one scheduling helper
- Add a debug assertion in shared code that dispatch is never called with RealtimeAudio
- Test audio paths on Windows specifically - it is the platform that enforces this invariant with a panic
When it happens
Trigger: Calling executor.dispatch(runnable, Priority::RealtimeAudio) directly, or building a task with RealtimeAudio priority and spawning it through a path that ends in WindowsDispatcher::dispatch instead of spawn_realtime (custom spawners, ported extension code, code written against a platform that does not enforce the split).
Common situations: App or extension authors adding audio work who copy the generic background-spawn pattern but set Priority::RealtimeAudio; refactors that change which spawn function a task flows through; porting code between platforms where only Windows enforces the contract.
Related errors
- RealtimeAudio priority should use spawn_realtime, not dispat
- Device lost: {err}
- blocking sender returned without value
- Error when registering clipboard format: {}
- Device lost: {err}
AI-assisted analysis of zed-industries/zed@f4178619ac (2026-08-20).
Data as JSON: /api/errors/9f6d8653668b8aab.
Report an issue: GitHub.