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
- Confirm the exact identifier: print resolve keys via collect_node_types() and compare against graphene_std::brush::brush::brush::IDENTIFIER.
- 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.
- If the node was removed from the registry intentionally, gate the brush tool's availability on the lookup succeeding instead of expecting.
- 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
- Keep the brush node registration and the brush::brush::brush import path in the same module-ownership review set.
- Smoke-test the first brush stroke after touching graphene_std::brush or the node registry.
- Gate the brush tool's availability on the registry lookup result so a missing node disables the tool rather than crashing.
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
- Spline node does not exist
- Star node can't be found
- Path node does not exist
- Path node does not exist
- Path node does not exist
AI-assisted analysis of GraphiteEditor/Graphite@c507b35645 (2026-08-16).
Data as JSON: /api/errors/3419996c9b619fdc.
Report an issue: GitHub.