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 {
				None

View on GitHub (pinned to c507b35645)

Solutions

  1. Verify the Image node registration (raster_nodes::std_nodes::image::IDENTIFIER) in the registry population code and remove any feature gating that excludes it.
  2. Import the identifier by constant path so upstream renames or moves surface at compile time.
  3. Populate the node registry during startup before message handling begins.
  4. 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

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.