{"record":{"id":"abcdfd9c5346b455","repo":"GraphiteEditor/Graphite","slug":"applicationio-not-available","errorCode":null,"errorMessage":"ApplicationIo not available","messagePattern":"ApplicationIo not available","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"node-graph/nodes/gstd/src/platform_application_io.rs","lineNumber":304,"sourceCode":"\t/// The scope-provided editor API giving access to the platform's resource storage.\n\t#[scope(editor_api::IDENTIFIER)]\n\teditor_api: Item<&'a PlatformEditorApi>,\n\t/// The content hash identifying which stored resource to load.\n\thash: Item<ResourceHash>,\n) -> Item<Resource> {\n\tlet hash = hash.into_element();\n\tlet application_io = editor_api.into_element().application_io.as_ref().expect(\"ApplicationIo must be available when using resources\");\n\tlet resource = application_io.load_resource(hash).await.unwrap_or_else(|| panic!(\"Resource {hash} not found\"));\n\tItem::new_from_element(resource)\n}\n\n#[node_macro::node(category(\"\"), inject_scope)]\npub async fn wgpu_executor<'a: 'n>(_: impl Ctx, #[scope(editor_api::IDENTIFIER)] editor_api: Item<&'a PlatformEditorApi>) -> Item<&'a ::wgpu_executor::WgpuExecutor> {\n\tlet executor = editor_api\n\t\t.into_element()\n\t\t.application_io\n\t\t.as_ref()\n\t\t.expect(\"ApplicationIo not available\")\n\t\t.gpu_executor()\n\t\t.expect(\"GPU executor not available\");\n\tItem::new_from_element(executor)\n}\n\n#[node_macro::node(category(\"\"), inject_scope)]\npub async fn try_wgpu_executor<'a: 'n>(_: impl Ctx, #[scope(editor_api::IDENTIFIER)] editor_api: Item<&'a PlatformEditorApi>) -> Item<Option<&'a ::wgpu_executor::WgpuExecutor>> {\n\tlet executor = editor_api.into_element().application_io.as_ref().and_then(|application_io| application_io.gpu_executor());\n\tItem::new_from_element(executor)\n}\n\n/// Uploads image data from CPU memory into a GPU texture so that GPU-based nodes can process it.\n#[node_macro::node(category(\"Debug\"), memoize)]\npub 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>> {\n\tlet executor = executor.into_element();\n\tlet (raster, attributes) = content.into_parts();\n\n\tItem::from_parts(raster.convert(Footprint::DEFAULT, executor).await, attributes)","sourceCodeStart":286,"sourceCodeEnd":322,"githubUrl":"https://github.com/GraphiteEditor/Graphite/blob/c507b356453361e31638b8bff8f6d46b6da2961e/node-graph/nodes/gstd/src/platform_application_io.rs#L286-L322","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["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","Provide an ApplicationIo in the scope's editor_api entry so the platform stack is complete","Evaluate inside the platform that constructed PlatformEditorApi with application_io set","Propagate a proper evaluation error instead of .expect so hosts can report the missing backend"],"exampleFix":"// before: panics when the platform provides no IO\nlet executor = editor_api.into_element().application_io.as_ref().expect(\"ApplicationIo not available\").gpu_executor()...;\n\n// after: depend on the non-panicking variant and handle absence explicitly\nlet executor: Option<&WgpuExecutor> = try_wgpu_executor_result.into_element();\nmatch executor {\n    Some(executor) => gpu_path(executor).await,\n    None => cpu_fallback_path().await,\n}","handlingStrategy":"fallback","validationCode":"// Host-side: verify the platform IO backend exists before evaluating GPU-dependent graphs\nlet io_present = editor_api.application_io.is_some();\nif !io_present {\n    // route the graph to CPU nodes / inform the user before evaluation","typeGuard":"fn has_application_io(api: &PlatformEditorApi) -> bool {\n    api.application_io.is_some()\n}","tryCatchPattern":"let outcome = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| evaluate_gpu_graph(doc)));\nif outcome.is_err() {\n    // fall back to CPU evaluation or surface a 'GPU backend unavailable' message\n}","preventionTips":["Prefer the try_* (Option-returning) node variants whenever a backend may legitimately be absent","Declare required platform services per graph and validate them at load time, not at evaluation time","Sandbox graph evaluation so a missing-backend panic becomes a reportable node failure"],"tags":["rust","graphite","node-graph","wgpu","scope","platform-io","panic"],"backgroundTag":"missing-application-context","analyzedSha":"c507b356453361e31638b8bff8f6d46b6da2961e","analyzedAt":"2026-08-16T21:57:18.596Z","schemaVersion":2},"datasetVersion":"2026-08-16T23:17:17.608Z"}