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,
) -> CachedRegion

View on GitHub (pinned to c507b35645)

Solutions

  1. Reuse the existing direct-render fallback when the executor is absent instead of unwrapping it (see exampleFix)
  2. Ensure the environment supplies a GPU executor: working adapter/driver, WebGPU enabled, or a software adapter
  3. Detect absence up front with the try_wgpu_executor Option and route the whole render through the non-cached path before evaluating
  4. 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 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


AI-assisted analysis of GraphiteEditor/Graphite@c507b35645 (2026-08-16). Data as JSON: /api/errors/e8bdf8c4403dfff4. Report an issue: GitHub.