{"record":{"id":"c492edae427dc6a5","repo":"GraphiteEditor/Graphite","slug":"image-node-does-not-exist","errorCode":null,"errorMessage":"Image node does not exist","messagePattern":"Image node does not exist","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"editor/src/messages/portfolio/document/graph_operation/utility_types.rs","lineNumber":286,"sourceCode":"\t\t}\n\n\t\tself.network_interface.set_input(&attachment_input, NodeInput::node(*node_id, 0), &[]);\n\t\tself.network_interface.set_chain_position(node_id, &[]);\n\t}\n\n\tpub fn insert_image_data(&mut self, image: Image<Color>, layer: LayerNodeIdentifier) {\n\t\tlet transform = resolve_proto_node_type(graphene_std::transform_nodes::transform::IDENTIFIER)\n\t\t\t.expect(\"Transform node does not exist\")\n\t\t\t.default_node_template();\n\n\t\tlet resource_id = ResourceId::new();\n\t\tself.responses.add(ResourceMessage::StoreEmbedded {\n\t\t\tresource_id,\n\t\t\tdata: image.to_png().into(),\n\t\t});\n\n\t\tlet image_node = resolve_proto_node_type(graphene_std::raster_nodes::std_nodes::image::IDENTIFIER)\n\t\t\t.expect(\"Image node does not exist\")\n\t\t\t.node_template_input_override([Some(NodeInput::value(TaggedValue::Resource(resource_id), false))]);\n\n\t\tlet image_node_id = NodeId::new();\n\t\tself.network_interface.insert_node(image_node_id, image_node, &[]);\n\t\tself.network_interface.move_node_to_chain_start(&image_node_id, layer, &[], self.import);\n\n\t\tlet transform_id = NodeId::new();\n\t\tself.network_interface.insert_node(transform_id, transform, &[]);\n\t\tself.network_interface.move_node_to_chain_start(&transform_id, layer, &[], self.import);\n\t}\n\n\tfn get_output_layer(&self) -> Option<LayerNodeIdentifier> {\n\t\tself.layer_node.or_else(|| {\n\t\t\tlet export_node = self.network_interface.document_network().exports.first().and_then(|export| export.as_node())?;\n\t\t\tif self.network_interface.is_layer(&export_node, &[]) {\n\t\t\t\tSome(LayerNodeIdentifier::new(export_node, self.network_interface))\n\t\t\t} else {\n\t\t\t\tNone","sourceCodeStart":268,"sourceCodeEnd":304,"githubUrl":"https://github.com/GraphiteEditor/Graphite/blob/c507b356453361e31638b8bff8f6d46b6da2961e/editor/src/messages/portfolio/document/graph_operation/utility_types.rs#L268-L304","documentation":"Invariant panic in insert_image_data. resolve_proto_node_type resolves the Image raster node (graphene_std::raster_nodes::std_nodes::image::IDENTIFIER) — the node that samples the embedded PNG resource stored moments earlier via ResourceMessage::StoreEmbedded — and the .expect fires when the registry returns None. Without the Image node the insert-image flow cannot create the layer content node, so the whole operation panics.","triggerScenarios":"Any image insertion (paste, drop, import into a layer) when the Image node type is missing from the proto-node registry: raster node registrations feature-gated out of the build, IDENTIFIER moved or renamed in graphene_std::raster_nodes, or document messages handled before registry population.","commonSituations":"Forks trimming raster nodes from the build; graphene_std upgrades that move std_nodes::image; test environments dispatching document messages without the full registry setup.","solutions":["Verify the Image node registration (raster_nodes::std_nodes::image::IDENTIFIER) in the registry population code and remove any feature gating that excludes it.","Import the identifier by constant path so upstream renames or moves surface at compile time.","Populate the node registry during startup before message handling begins.","Replace .expect with let-else plus log::error! and an early return so a missing node disables image import gracefully."],"exampleFix":"// before\nlet image_node = resolve_proto_node_type(graphene_std::raster_nodes::std_nodes::image::IDENTIFIER)\n\t.expect(\"Image node does not exist\")\n\t.node_template_input_override([Some(NodeInput::value(TaggedValue::Resource(resource_id), false))]);\n\n// after\nlet Some(image_node) = resolve_proto_node_type(graphene_std::raster_nodes::std_nodes::image::IDENTIFIER) else {\n\tlog::error!(\"Image node type not registered; cannot insert image\");\n\treturn;\n};\nlet image_node = image_node.node_template_input_override([Some(NodeInput::value(TaggedValue::Resource(resource_id), false))]);","handlingStrategy":"validation","validationCode":"// gate image import UI/shortcuts on both required nodes being registered\nfn can_insert_images() -> bool {\n\tproto_node_registered(graphene_std::raster_nodes::std_nodes::image::IDENTIFIER)\n\t\t&& proto_node_registered(graphene_std::transform_nodes::transform::IDENTIFIER)\n}","typeGuard":"fn proto_node_registered(identifier: NodeIdentifier) -> bool {\n\tresolve_proto_node_type(identifier).is_some()\n}","tryCatchPattern":"// no idiomatic catch; isolate at the message-dispatch boundary if required\nlet outcome = std::panic::catch_unwind(std::assert_unwind_safe(|| {\n\thandler.insert_image_data(image.clone(), layer);\n}));\nif outcome.is_err() { log::error!(\"image insert aborted: node types missing\"); }","preventionTips":["Register all raster and transform nodes in one place that cannot be feature-gated piecemeal","Import IDENTIFIER constants by path so upstream renames break compilation, not runtime","Test the full paste-image flow in CI, not just registry population"],"tags":["rust","graphite","node-registry","panic","raster","image-import"],"backgroundTag":"node-registry-lookup-failed","analyzedSha":"c507b356453361e31638b8bff8f6d46b6da2961e","analyzedAt":"2026-08-16T21:57:18.596Z","schemaVersion":2},"datasetVersion":"2026-08-16T23:17:17.608Z"}