GraphiteEditor/Graphite · error

Solidify Stroke node should exist

Error message

Solidify Stroke node should exist

What it means

Panics when `document_node_definitions::resolve_proto_node_type(graphene_std::vector::solidify_stroke::IDENTIFIER)` returns `None`. The function looks the node up in the static `DOCUMENT_NODE_TYPES` registry (document_node_definitions.rs:1480-1486); the Graphite editor assumes every proto node its handlers reference is registered there at build time. The expect is a static-invariant assertion: it can only fire if the registry and the `solidify_stroke` IDENTIFIER constant have drifted apart (rename, move, or missing registration).

Source

Thrown at editor/src/messages/portfolio/document/document_message_handler.rs:2746

				new_folders.push(DocumentMessageHandler::group_layers(responses, insert_index, parent, group_folder_type, &mut self.network_interface));
			}

			responses.add(NodeGraphMessage::SelectedNodesSet { nodes: new_folders });
		}
	}

	/// For each selected layer, splits its fill and stroke into two stacked layers connected
	/// to a shared `Solidify Stroke` node via two `Item at Index` nodes (indices 0 and 1).
	/// Layers with only a stroke get just a `Solidify Stroke` added.
	/// Layers with only a fill, or neither, are left untouched.
	fn handle_expand_fill_stroke_on_selected_layers(&mut self, responses: &mut VecDeque<Message>) {
		let selected_layers: Vec<LayerNodeIdentifier> = self.network_interface.selected_nodes().selected_layers(self.metadata()).collect();
		if selected_layers.is_empty() {
			return;
		}

		let solidify_stroke_definition = document_node_definitions::resolve_proto_node_type(graphene_std::vector::solidify_stroke::IDENTIFIER).expect("Solidify Stroke node should exist");
		let item_at_index_definition = document_node_definitions::resolve_proto_node_type(graphene_std::graphic::item_at_index::IDENTIFIER).expect("Item at Index node should exist");

		let mut resulting_layers: Vec<NodeId> = Vec::new();

		for layer in selected_layers {
			if !self.network_interface.document_metadata().layer_vector_data.contains_key(&layer) {
				resulting_layers.push(layer.to_node());
				continue;
			}

			let appearance = self.network_interface.document_metadata().layer_appearance_attributes.get(&layer);

			let has_fill = appearance.is_some_and(|appearance| appearance.has_painted_cover(Cover::Fill));
			// A visible stroke needs both renderable geometry (non-zero weight) and paint that draws something
			let has_stroke = appearance.is_some_and(|appearance| {
				appearance.first_coverage_of(Cover::Stroke).is_some_and(|coverage| coverage.stroke_params().has_renderable_stroke())
					&& appearance.first_paint_of(Cover::Stroke).is_some_and(|paint| !paint.is_guaranteed_fully_transparent())
			});

View on GitHub (pinned to c507b35645)

Solutions

  1. Confirm the registry entry exists: search `DOCUMENT_NODE_TYPES` / the generate-registry macro in `editor/src/messages/portfolio/document/node_graph/document_node_definitions.rs` for the Solidify Stroke definition.
  2. If the node was renamed or moved, restore the old `IDENTIFIER` value in `graphene_std::vector::solidify_stroke` or update the call site to the new identifier.
  3. If this is a new node, add its `DocumentNodeDefinition` to the registry (correct `ProtoNodeIdentifier`, category, and template).
  4. Replace the `expect` with graceful `Option` handling (log and return) so a registry drift degrades instead of crashing the editor.

Example fix

// before
let solidify_stroke_definition = document_node_definitions::resolve_proto_node_type(graphene_std::vector::solidify_stroke::IDENTIFIER).expect("Solidify Stroke node should exist");

// after
let Some(solidify_stroke_definition) = document_node_definitions::resolve_proto_node_type(graphene_std::vector::solidify_stroke::IDENTIFIER) else {
    log::error!("Solidify Stroke node definition is not registered; skipping expand fill/stroke");
    return;
};
Defensive patterns

Strategy: validation

Validate before calling

// Before running the expand fill/stroke command, confirm the definitions exist:
let ok = [
    graphene_std::vector::solidify_stroke::IDENTIFIER,
    graphene_std::graphic::item_at_index::IDENTIFIER,
].iter().all(|id| document_node_definitions::resolve_proto_node_type(*id).is_some());
if !ok {
    log::error!("Expand Fill/Stroke unavailable: required node definitions not registered");
    return;
}

Type guard

fn solidify_stroke_registered() -> bool {
    document_node_definitions::resolve_proto_node_type(graphene_std::vector::solidify_stroke::IDENTIFIER).is_some()
}

Try / catch

// Rust has no try/catch; isolate the panic at a boundary if unavoidable:
let template = std::panic::catch_unwind(|| {
    document_node_definitions::resolve_proto_node_type(graphene_std::vector::solidify_stroke::IDENTIFIER)
        .map(|d| d.default_node_template())
});
if template.is_err() {
    log::error!("solidify stroke lookup panicked; registry is inconsistent");
}

Prevention

When it happens

Trigger: Invoked from `handle_expand_fill_stroke_on_selected_layers`, i.e. the user runs the Expand Fill/Stroke command on one or more selected layers. The panic fires only when the `Solidify Stroke` proto node definition is absent from `DOCUMENT_NODE_TYPES` — e.g. the node was renamed in graphene_std, moved modules, its `IDENTIFIER` constant changed, or it was never added to the node registry list.

Common situations: Renaming a proto node struct or its `IDENTIFIER` without updating `document_node_definitions.rs`; moving `solidify_stroke` between crates/modules; adding a new node to graphene_std but forgetting the registry entry; builds where a feature flag excludes the node definition module.

Related errors


AI-assisted analysis of GraphiteEditor/Graphite@c507b35645 (2026-08-16). Data as JSON: /api/errors/1ae71c10d40d3ef9. Report an issue: GitHub.