GraphiteEditor/Graphite · error

ApplicationIo not available

Error message

ApplicationIo not available

What it means

The wgpu_executor node resolves the GPU executor from the scope-provided PlatformEditorApi and .expect("ApplicationIo not available") panics when application_io is None, i.e. the evaluation environment has no platform IO backend at all. It is the first of two assertions in this node; the second (line 306) additionally requires a GPU executor inside the ApplicationIo. The sibling try_wgpu_executor node in the same file returns Option and never panics, existing precisely for environments where these backends may be absent.

Source

Thrown at node-graph/nodes/gstd/src/platform_application_io.rs:304

	/// The scope-provided editor API giving access to the platform's resource storage.
	#[scope(editor_api::IDENTIFIER)]
	editor_api: Item<&'a PlatformEditorApi>,
	/// The content hash identifying which stored resource to load.
	hash: Item<ResourceHash>,
) -> Item<Resource> {
	let hash = hash.into_element();
	let application_io = editor_api.into_element().application_io.as_ref().expect("ApplicationIo must be available when using resources");
	let resource = application_io.load_resource(hash).await.unwrap_or_else(|| panic!("Resource {hash} not found"));
	Item::new_from_element(resource)
}

#[node_macro::node(category(""), inject_scope)]
pub async fn wgpu_executor<'a: 'n>(_: impl Ctx, #[scope(editor_api::IDENTIFIER)] editor_api: Item<&'a PlatformEditorApi>) -> Item<&'a ::wgpu_executor::WgpuExecutor> {
	let executor = editor_api
		.into_element()
		.application_io
		.as_ref()
		.expect("ApplicationIo not available")
		.gpu_executor()
		.expect("GPU executor not available");
	Item::new_from_element(executor)
}

#[node_macro::node(category(""), inject_scope)]
pub async fn try_wgpu_executor<'a: 'n>(_: impl Ctx, #[scope(editor_api::IDENTIFIER)] editor_api: Item<&'a PlatformEditorApi>) -> Item<Option<&'a ::wgpu_executor::WgpuExecutor>> {
	let executor = editor_api.into_element().application_io.as_ref().and_then(|application_io| application_io.gpu_executor());
	Item::new_from_element(executor)
}

/// Uploads image data from CPU memory into a GPU texture so that GPU-based nodes can process it.
#[node_macro::node(category("Debug"), memoize)]
pub async fn upload_texture<'a: 'n>(_: impl Ctx, content: Item<Raster<CPU>>, #[scope(wgpu_executor::IDENTIFIER)] executor: Item<&'a ::wgpu_executor::WgpuExecutor>) -> Item<Raster<GPU>> {
	let executor = executor.into_element();
	let (raster, attributes) = content.into_parts();

	Item::from_parts(raster.convert(Footprint::DEFAULT, executor).await, attributes)

View on GitHub (pinned to c507b35645)

Solutions

  1. Switch the graph to the try_wgpu_executor node (same file), which yields Item<Option<&WgpuExecutor>> and lets you branch to CPU processing instead of panicking
  2. Provide an ApplicationIo in the scope's editor_api entry so the platform stack is complete
  3. Evaluate inside the platform that constructed PlatformEditorApi with application_io set
  4. Propagate a proper evaluation error instead of .expect so hosts can report the missing backend

Example fix

// before: panics when the platform provides no IO
let executor = editor_api.into_element().application_io.as_ref().expect("ApplicationIo not available").gpu_executor()...;

// after: depend on the non-panicking variant and handle absence explicitly
let executor: Option<&WgpuExecutor> = try_wgpu_executor_result.into_element();
match executor {
    Some(executor) => gpu_path(executor).await,
    None => cpu_fallback_path().await,
}
Defensive patterns

Strategy: fallback

Validate before calling

// Host-side: verify the platform IO backend exists before evaluating GPU-dependent graphs
let io_present = editor_api.application_io.is_some();
if !io_present {
    // route the graph to CPU nodes / inform the user before evaluation

Type guard

fn has_application_io(api: &PlatformEditorApi) -> bool {
    api.application_io.is_some()
}

Try / catch

let outcome = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| evaluate_gpu_graph(doc)));
if outcome.is_err() {
    // fall back to CPU evaluation or surface a 'GPU backend unavailable' message
}

Prevention

When it happens

Trigger: Evaluating any graph that requests the wgpu_executor scope dependency (GPU raster nodes, upload_texture, render nodes) in an environment whose editor_api carries application_io = None: headless test hosts, CLI pipelines, or custom graph hosts that inject PlatformEditorApi without platform IO.

Common situations: Running GPU-dependent documents in CI; embedding the node graph in a custom application that forgot to provide platform IO; platform ports mid-development; tests that construct a minimal scope and then touch GPU nodes.

Related errors


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