{"record":{"id":"2fb5f19885b5c0c7","repo":"GraphiteEditor/Graphite","slug":"applicationio-must-be-available-when-using-resourc","errorCode":null,"errorMessage":"ApplicationIo must be available when using resources","messagePattern":"ApplicationIo must be available when using resources","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"node-graph/nodes/gstd/src/platform_application_io.rs","lineNumber":293,"sourceCode":"\t)\n}\n\n#[node_macro::node(category(\"\"), inject_scope)]\npub async fn editor_api<'a: 'n>(_: impl Ctx, #[scope(\"editor-api\")] editor_api: Item<&'a PlatformEditorApi>) -> Item<&'a PlatformEditorApi> {\n\teditor_api\n}\n\n#[node_macro::node(category(\"\"))]\npub async fn resource<'a: 'n>(\n\t_: impl Ctx,\n\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>> {","sourceCodeStart":275,"sourceCodeEnd":311,"githubUrl":"https://github.com/GraphiteEditor/Graphite/blob/c507b356453361e31638b8bff8f6d46b6da2961e/node-graph/nodes/gstd/src/platform_application_io.rs#L275-L311","documentation":"The resource node in gstd loads a stored platform resource by content hash through the PlatformEditorApi injected from the graph scope, and .expect panics when the editor API carries no ApplicationIo (the platform's IO backend that owns resource storage). This means the graph was evaluated in an environment that does not provide platform resource storage: headless tests, CLI/WASM hosts, or a scope where the editor_api entry was registered without application_io.","triggerScenarios":"Evaluating a document containing the resource node outside the full editor platform; hosting the node graph yourself and injecting an editor_api::IDENTIFIER scope item whose application_io field is None; programmatic graph evaluation in tests or an export pipeline with no platform IO wired up.","commonSituations":"Editor-authored graphs run in CI; a new platform port that has not wired ApplicationIo yet; refactors that change how PlatformEditorApi is constructed so application_io is left unset in some builds.","solutions":["Run or evaluate the graph inside the platform/editor that constructs PlatformEditorApi with application_io set, so resource storage is reachable","If you host evaluation yourself, provide an ApplicationIo implementation (resource load/store backend) on the editor_api scope entry before evaluating resource nodes","Replace the .expect with an explicit evaluation error so a missing platform backend surfaces as a node failure instead of a panic","For portable/headless graphs, avoid the resource node: load the data through your own IO and feed it into the graph directly"],"exampleFix":"// before (host evaluates graph, scope lacks IO)\nlet application_io = editor_api.into_element().application_io.as_ref().expect(\"ApplicationIo must be available when using resources\");\n\n// after (host side): construct the scope entry with the platform IO present so the expect never fires\nlet editor_api = PlatformEditorApi { application_io: Some(platform_io), /* ... */ };\n// then insert it under editor_api::IDENTIFIER before evaluating the document","handlingStrategy":"validation","validationCode":"// Host-side: before evaluating a graph containing resource nodes, verify the scope provides platform IO\nlet has_io = scope\n    .extract::<&PlatformEditorApi>(editor_api::IDENTIFIER)\n    .map(|api| api.application_io.is_some())\n    .unwrap_or(false);\nif !has_io {\n    // skip evaluation, or provide an ApplicationIo before running resource nodes\n}","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_document(doc)));\nif outcome.is_err() {\n    // report the failing resource node (message starts with \"ApplicationIo must be available\") instead of crashing the host\n}","preventionTips":["Treat resource nodes as editor-only: exclude them from graphs meant for headless/CI evaluation","When hosting graph evaluation, always construct the editor_api scope entry with an ApplicationIo implementation","Evaluate graphs in a sandboxed worker with catch_unwind so one node's panic cannot take down the host"],"tags":["rust","graphite","node-graph","scope","platform-io","resource","panic"],"backgroundTag":"missing-application-context","analyzedSha":"c507b356453361e31638b8bff8f6d46b6da2961e","analyzedAt":"2026-08-16T21:57:18.596Z","schemaVersion":2},"datasetVersion":"2026-08-16T23:17:17.608Z"}