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

MacDispatcher::dispatch maps GPUI Priority to libdispatch global queue priorities; RealtimeAudio has no global-queue equivalent — realtime audio work must run on a dedicated realtime thread via the spawn_realtime APIs. Calling dispatch with Priority::RealtimeAudio is a programming error and panics immediately with that instruction.

Source

Thrown at crates/gpui_macos/src/dispatcher.rs:44

impl MacDispatcher {
    pub fn new() -> Self {
        Self
    }
}

impl PlatformDispatcher for MacDispatcher {
    fn is_main_thread(&self) -> bool {
        let is_main_thread: BOOL = unsafe { msg_send![class!(NSThread), isMainThread] };
        is_main_thread == YES
    }

    fn dispatch(&self, runnable: RunnableVariant, priority: Priority) {
        let context = runnable.into_raw().as_ptr() as *mut c_void;

        let queue_priority = match priority {
            Priority::RealtimeAudio => {
                panic!("RealtimeAudio priority should use spawn_realtime, not dispatch")
            }
            Priority::High => DispatchQueueGlobalPriority::High,
            Priority::Medium => DispatchQueueGlobalPriority::Default,
            Priority::Low => DispatchQueueGlobalPriority::Low,
        };

        unsafe {
            DispatchQueue::global_queue(GlobalQueueIdentifier::Priority(queue_priority))
                .exec_async_f(context, trampoline);
        }
    }

    fn dispatch_on_main_thread(&self, runnable: RunnableVariant, _priority: Priority) {
        let context = runnable.into_raw().as_ptr() as *mut c_void;
        unsafe {
            DispatchQueue::main().exec_async_f(context, trampoline);
        }
    }

View on GitHub (pinned to 9d272b0363)

Solutions

  1. Use the realtime spawn APIs (PlatformDispatcher::spawn_realtime) for RealtimeAudio-priority work instead of dispatch
  2. If the work is not truly realtime audio, use Priority::High which maps to a libdispatch high-priority global queue
  3. Audit any code path that constructs Priority values dynamically before dispatching

Example fix

// before
dispatcher.dispatch(runnable, Priority::RealtimeAudio); // panic on macOS

// after
dispatcher.spawn_realtime(async move { /* audio work */ });
Defensive patterns

Strategy: validation

Validate before calling

if let Priority::RealtimeAudio = priority {
    dispatcher.spawn_realtime(fut); // correct path for realtime audio
} else {
    dispatcher.dispatch(runnable, priority);
}

Type guard

fn is_dispatchable_priority(priority: Priority) -> bool {
    !matches!(priority, Priority::RealtimeAudio)
}

Prevention

When it happens

Trigger: Calling `dispatcher.dispatch(runnable, Priority::RealtimeAudio)` in GPUI code on macOS — typically new code choosing the wrong priority, or code ported from a platform whose dispatcher accepted it.

Common situations: Contributors adding audio-related tasks and reusing dispatch with the realtime priority; refactors that move spawn_realtime work into plain dispatch calls.

Related errors


AI-assisted analysis of zed-industries/zed@9d272b0363 (2026-08-20). Data as JSON: /api/errors/0ebf54624edb51e0. Report an issue: GitHub.