GraphiteEditor/Graphite · error
Image node does not exist
Error message
Image node does not exist
What it means
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.
Source
Thrown at editor/src/messages/portfolio/document/graph_operation/utility_types.rs:286
}
self.network_interface.set_input(&attachment_input, NodeInput::node(*node_id, 0), &[]);
self.network_interface.set_chain_position(node_id, &[]);
}
pub fn insert_image_data(&mut self, image: Image<Color>, layer: LayerNodeIdentifier) {
let transform = resolve_proto_node_type(graphene_std::transform_nodes::transform::IDENTIFIER)
.expect("Transform node does not exist")
.default_node_template();
let resource_id = ResourceId::new();
self.responses.add(ResourceMessage::StoreEmbedded {
resource_id,
data: image.to_png().into(),
});
let image_node = resolve_proto_node_type(graphene_std::raster_nodes::std_nodes::image::IDENTIFIER)
.expect("Image node does not exist")
.node_template_input_override([Some(NodeInput::value(TaggedValue::Resource(resource_id), false))]);
let image_node_id = NodeId::new();
self.network_interface.insert_node(image_node_id, image_node, &[]);
self.network_interface.move_node_to_chain_start(&image_node_id, layer, &[], self.import);
let transform_id = NodeId::new();
self.network_interface.insert_node(transform_id, transform, &[]);
self.network_interface.move_node_to_chain_start(&transform_id, layer, &[], self.import);
}
fn get_output_layer(&self) -> Option<LayerNodeIdentifier> {
self.layer_node.or_else(|| {
let export_node = self.network_interface.document_network().exports.first().and_then(|export| export.as_node())?;
if self.network_interface.is_layer(&export_node, &[]) {
Some(LayerNodeIdentifier::new(export_node, self.network_interface))
} else {
NoneView on GitHub (pinned to c507b35645)
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.
Example fix
// before
let image_node = resolve_proto_node_type(graphene_std::raster_nodes::std_nodes::image::IDENTIFIER)
.expect("Image node does not exist")
.node_template_input_override([Some(NodeInput::value(TaggedValue::Resource(resource_id), false))]);
// after
let Some(image_node) = resolve_proto_node_type(graphene_std::raster_nodes::std_nodes::image::IDENTIFIER) else {
log::error!("Image node type not registered; cannot insert image");
return;
};
let image_node = image_node.node_template_input_override([Some(NodeInput::value(TaggedValue::Resource(resource_id), false))]); Defensive patterns
Strategy: validation
Validate before calling
// gate image import UI/shortcuts on both required nodes being registered
fn can_insert_images() -> bool {
proto_node_registered(graphene_std::raster_nodes::std_nodes::image::IDENTIFIER)
&& proto_node_registered(graphene_std::transform_nodes::transform::IDENTIFIER)
} Type guard
fn proto_node_registered(identifier: NodeIdentifier) -> bool {
resolve_proto_node_type(identifier).is_some()
} Try / catch
// no idiomatic catch; isolate at the message-dispatch boundary if required
let outcome = std::panic::catch_unwind(std::assert_unwind_safe(|| {
handler.insert_image_data(image.clone(), layer);
}));
if outcome.is_err() { log::error!("image insert aborted: node types missing"); } Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
AI-assisted analysis of GraphiteEditor/Graphite@c507b35645 (2026-08-16).
Data as JSON: /api/errors/c492edae427dc6a5.
Report an issue: GitHub.