zed-industries/zed · error

validated in BenchAppContext::build

Error message

validated in BenchAppContext::build

What it means

`BenchAppContext::run_until_idle` calls `background_executor.dispatcher().as_threaded().expect("validated in BenchAppContext::build")`. This panics because the dispatcher behind the context's executors is not a `ThreadedDispatcher`. The library normally guarantees this in `BenchAppContext::build` (an assert on line 533 requires a platform constructed via `gpui::bench_platform`), so hitting the expect means the context was built against a non-threaded platform — typically the deterministic test platform used by `TestAppContext` — bypassing that validation.

Source

Thrown at crates/gpui/src/app/bench_context.rs:592

    }

    /// Reads app state.
    pub fn read<R>(&self, read: impl FnOnce(&App) -> R) -> R {
        let app = self.app.borrow();
        read(&app)
    }

    /// Runs queued foreground tasks on this thread and waits for in flight
    /// background work to finish. Timers that aren't due yet are not waited
    /// for (see [`ThreadedDispatcher::run_until_idle`]). Scheduled frames are
    /// delivered after each task poll and when there are no ready tasks, but
    /// animations alone do not keep this method running.
    pub fn run_until_idle(&self) {
        let dispatcher = self
            .background_executor
            .dispatcher()
            .as_threaded()
            .expect("validated in BenchAppContext::build");
        dispatcher.run_until_idle_with(|| {
            let ran_tasks = dispatcher.run_ready_main_tasks_with(
                || true,
                || {
                    self.dispatch_pending_frames(|| true);
                },
            );
            if !ran_tasks {
                self.dispatch_pending_frames(|| true);
            }
            ran_tasks
        });
    }

    /// Alternates draining queued work with GPUI update cycles until neither
    /// makes progress, so state dropped by benchmark code is fully released.
    ///
    /// Dropped entities are released only inside an update's effect flush, and

View on GitHub (pinned to 9d272b0363)

Solutions

  1. Construct the platform with `gpui::bench_platform(headless_renderer_factory, text_system)` so its executors are backed by a `ThreadedDispatcher`.
  2. Ensure the `BenchAppContext` is created via its normal `build` constructor, which asserts the dispatcher is threaded (the panic message's 'validated in BenchAppContext::build' invariant).
  3. If you are writing a plain unit test rather than a benchmark, use `TestAppContext`/`gpui::test` instead of `BenchAppContext`.
  4. If a custom platform is required, implement `PlatformDispatcher::as_threaded` to return `Some(&ThreadedDispatcher)`.

Example fix

// before
let platform = TestPlatform::new();
let cx = BenchAppContext::build(platform, ...);
cx.run_until_idle(); // panics: not a ThreadedDispatcher

// after
let platform = gpui::bench_platform(None, text_system);
let cx = BenchAppContext::build(platform, ...);
cx.run_until_idle();
Defensive patterns

Strategy: validation

Validate before calling

if cx.background_executor.dispatcher().as_threaded().is_none() {
    panic!("BenchAppContext requires a platform built with gpui::bench_platform");
}

Type guard

fn is_bench_platform(executor: &BackgroundExecutor) -> bool {
    executor.dispatcher().as_threaded().is_some()
}

Prevention

When it happens

Trigger: Calling `run_until_idle()` (directly or via `settle()`, `add_empty_window()`, or `teardown()`) on a `BenchAppContext` whose platform was not constructed with `gpui::bench_platform` — e.g. constructing the context with a `TestPlatform` backed by a deterministic/single-threaded dispatcher, or swapping the executor after build.

Common situations: Reusing a test harness's `TestPlatform` for a benchmark instead of calling `bench_platform`; wiring a custom `Platform` implementation whose `dispatcher()` returns a non-threaded dispatcher; copy-pasting `TestAppContext` setup code into a `#[gpui::bench]` benchmark.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


AI-assisted analysis of zed-industries/zed@9d272b0363 (2026-09-12). Data as JSON: /api/errors/bc939c1feda39de6. Report an issue: GitHub.