GraphiteEditor/Graphite · error
GPU executor not available
Error message
GPU executor not available
What it means
The tiled render-cache node composites cached/new render regions into a GPU output texture via executor.request_texture(...) and composite_cached_regions(...); executor.into_element().expect("GPU executor not available") panics when the scope-provided executor slot (an Option, same as the render node) is None. Notably the function already has a direct-render fallback for the no-regions and zero-size cases, but the tiled compositing path unconditionally requires the GPU, so a missing executor aborts evaluation as soon as there is anything to composite.
Source
Thrown at node-graph/nodes/gstd/src/render_cache.rs:393
for missing_region in &cache_query.missing_regions {
if missing_region.tiles.is_empty() {
continue;
}
let region = render_missing_region(missing_region, |ctx| data.eval(ctx), ctx.clone(), render_params, &footprint.transform, &device_origin_offset).await;
new_regions.push(region);
}
tile_cache.store_regions(new_regions.clone());
let all_regions: Vec<_> = cache_query.cached_regions.into_iter().chain(new_regions).collect();
// If no regions, fall back to direct render
if all_regions.is_empty() {
let context = OwnedContextImpl::from(ctx.clone()).with_footprint(*footprint).with_vararg(Box::new(render_params.clone()));
return data.eval(context.into_context()).await;
}
let executor = executor.into_element().expect("GPU executor not available");
let output_texture = executor.request_texture(physical_resolution).await;
let combined_metadata = composite_cached_regions(&all_regions, &output_texture, &device_origin_offset, &footprint.transform, executor);
Item::new_from_element(RenderOutput {
data: RenderOutputType::Texture(output_texture),
metadata: combined_metadata,
})
}
async fn render_missing_region<F, Fut>(
region: &RenderRegion,
render_fn: F,
ctx: impl Ctx + ExtractAll + CloneVarArgs,
render_params: &RenderParams,
viewport_transform: &DAffine2,
viewport_origin_offset: &DVec2,
) -> CachedRegionView on GitHub (pinned to c507b35645)
Solutions
- Reuse the existing direct-render fallback when the executor is absent instead of unwrapping it (see exampleFix)
- Ensure the environment supplies a GPU executor: working adapter/driver, WebGPU enabled, or a software adapter
- Detect absence up front with the try_wgpu_executor Option and route the whole render through the non-cached path before evaluating
- Propagate an evaluation error instead of .expect so hosts can degrade to CPU rendering
Example fix
// before
let executor = executor.into_element().expect("GPU executor not available");
let output_texture = executor.request_texture(physical_resolution).await;
// after: reuse the existing direct-render fallback when no GPU executor is in scope
let Some(executor) = executor.into_element() else {
let context = OwnedContextImpl::from(ctx.clone()).with_footprint(*footprint).with_vararg(Box::new(render_params.clone()));
return data.eval(context.into_context()).await;
};
let output_texture = executor.request_texture(physical_resolution).await; Defensive patterns
Strategy: fallback
Validate before calling
// The cache node's executor is the same Optional scope slot; check before evaluating cached renders
let executor: Option<&WgpuExecutor> = executor_slot.into_element();
if executor.is_none() {
// evaluate through the direct (non-cached) render path instead
} Type guard
fn can_composite_gpu(executor_slot: Option<&WgpuExecutor>) -> bool {
executor_slot.is_some()
} Try / catch
let outcome = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| render_output_cache.evaluate(ctx).await));
if outcome.is_err() {
// no GPU executor for compositing: re-evaluate through the direct render path and report the degraded mode
} Prevention
- When GPU availability is uncertain, evaluate renders through the direct path rather than the tiled cache path
- Detect a missing executor up front via try_wgpu_executor and skip cache compositing entirely
- After any GPU device loss, reset cached render state so cached paths do not run without an executor
- Sandbox evaluation so this panic becomes a node error with a CPU fallback
When it happens
Trigger: Tiled/cached rendering with at least one region to composite in an environment whose executor scope slot is None (no GPU adapter, GPU initialization failed, headless host); reaching line 393 after render_missing_region() and tile_cache.store_regions() have produced regions.
Common situations: Documents with render caching enabled opened on GPU-less or driver-broken machines; CI screenshot tests of cached documents; sessions where the wgpu device was lost and the executor slot became None; exports after the platform degraded to CPU.
Related errors
- ApplicationIo not available
- GPU executor not available
- GPU executor not available
- GPU executor should be available when we receive a texture
- ApplicationIo must be available when using resources
AI-assisted analysis of GraphiteEditor/Graphite@c507b35645 (2026-08-16).
Data as JSON: /api/errors/e8bdf8c4403dfff4.
Report an issue: GitHub.