GraphiteEditor/Graphite · error

Brush node does not exist

Error message

Brush node does not exist

What it means

new_brush_layer resolves the Brush proto node (graphene_std::brush::brush::brush::IDENTIFIER) in the DOCUMENT_NODE_TYPES static registry and panics on a miss. The brush node lives in a separate graphene_std::brush module tree, so this expect guards that the brush crate's node implementations were compiled into and registered by the editor build. It fires on the very first brush stroke in a session, because that is when the tool creates the hidden brush layer holding the brush node. Like all registry expects it signals a version/build mismatch between the call site and the registry, not bad user data.

Source

Thrown at editor/src/messages/tool/tool_messages/brush_tool.rs:465

				HintGroup(vec![HintInfo::mouse(MouseMotion::LmbDrag, "Draw")]),
				HintGroup(vec![HintInfo::multi_keys([[Key::BracketLeft], [Key::BracketRight]], "Shrink/Grow Brush")]),
			]),
			BrushToolFsmState::Drawing => HintData(vec![HintGroup(vec![HintInfo::mouse(MouseMotion::Rmb, ""), HintInfo::keys([Key::Escape], "Cancel").prepend_slash()])]),
		};

		hint_data.send_layout(responses);
	}

	fn update_cursor(&self, responses: &mut VecDeque<Message>) {
		responses.add(FrontendMessage::UpdateMouseCursor { cursor: MouseCursorIcon::Default });
	}
}

fn new_brush_layer(document: &DocumentMessageHandler, responses: &mut VecDeque<Message>) -> LayerNodeIdentifier {
	responses.add(DocumentMessage::DeselectAllLayers);

	let brush_node = resolve_proto_node_type(graphene_std::brush::brush::brush::IDENTIFIER)
		.expect("Brush node does not exist")
		.default_node_template();

	let id = NodeId::new();
	responses.add(GraphOperationMessage::NewCustomLayer {
		id,
		nodes: vec![(NodeId(0), brush_node)],
		parent: document.new_layer_parent(true),
		insert_index: 0,
	});
	responses.add(NodeGraphMessage::SelectedNodesSet { nodes: vec![id] });

	LayerNodeIdentifier::new_unchecked(id)
}

View on GitHub (pinned to c507b35645)

Solutions

  1. Confirm the exact identifier: print resolve keys via collect_node_types() and compare against graphene_std::brush::brush::brush::IDENTIFIER.
  2. If the module was restructured (the brush::brush::brush path is fragile), update the import at brush_tool.rs to the new path and keep referencing the IDENTIFIER constant, never a literal string.
  3. If the node was removed from the registry intentionally, gate the brush tool's availability on the lookup succeeding instead of expecting.
  4. Clean rebuild (cargo clean + build) after moving nodes between crates so the registry macro inputs are regenerated.

Example fix

// before
let brush_node = resolve_proto_node_type(graphene_std::brush::brush::brush::IDENTIFIER)
	.expect("Brush node does not exist")
	.default_node_template();

// after
let Some(brush_def) = resolve_proto_node_type(graphene_std::brush::brush::brush::IDENTIFIER) else {
	log::error!("Brush proto node not registered; cannot create brush layer");
	return LayerNodeIdentifier::ROOT_PARENT;
};
let brush_node = brush_def.default_node_template();
Defensive patterns

Strategy: validation

Validate before calling

fn brush_node_registered() -> bool {
	resolve_proto_node_type(graphene_std::brush::brush::brush::IDENTIFIER).is_some()
}

// before starting a brush session:
if !brush_node_registered() {
	// disable brush tool / show error instead of expecting
}

Prevention

When it happens

Trigger: Starting the first brush stroke when no brush layer exists yet: the brush tool FSM calls new_brush_layer(), which runs resolve_proto_node_type(graphene_std::brush::brush::brush::IDENTIFIER).expect("Brush node does not exist").default_node_template() before inserting the layer via NewCustomLayer.

Common situations: The brush node's IDENTIFIER or triple-nested brush::brush::brush module path was renamed in graphene_std; the brush node registration was dropped from document_node_definitions(); the brush feature is compiled out; a stale build mixes an old editor crate with new libraries.

Related errors


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