GraphiteEditor/Graphite · critical
Failed to create Spline node
Error message
Failed to create Spline node
What it means
Graphite resolves node blueprints through a process-wide static registry: DOCUMENT_NODE_TYPES, a Lazy<HashMap<DefinitionIdentifier, DocumentNodeDefinition>> built by document_node_definitions() (document_node_definitions.rs:130). resolve_proto_node_type() (document_node_definitions.rs:1480) returns None when the ProtoNodeIdentifier is not a key in that map, and this .expect() in the layer-merge helper (graph_modification_utils.rs:134-136) turns that None into a panic while building the Spline node. It signals a code/registration mismatch, not bad user data.
Source
Thrown at editor/src/messages/tool/common_functionality/graph_modification_utils.rs:135
// Add a path node after the combine paths node
let path_node_id = NodeId::new();
let path_node = document_node_definitions::resolve_network_node_type("Path")
.expect("Failed to create path node")
.default_node_template();
responses.add(NodeGraphMessage::InsertNode {
node_id: path_node_id,
node_template: Box::new(path_node),
});
responses.add(NodeGraphMessage::MoveNodeToChainStart {
node_id: path_node_id,
parent: first_layer,
});
// Add a Spline node after the Path node if both the layers we are merging is spline.
if current_and_other_layer_is_spline {
let spline_node_id = NodeId::new();
let spline_node = document_node_definitions::resolve_proto_node_type(graphene_std::vector::spline::IDENTIFIER)
.expect("Failed to create Spline node")
.default_node_template();
responses.add(NodeGraphMessage::InsertNode {
node_id: spline_node_id,
node_template: Box::new(spline_node),
});
responses.add(NodeGraphMessage::MoveNodeToChainStart {
node_id: spline_node_id,
parent: first_layer,
});
}
// Add a transform node to ensure correct tooling modifications
let transform_node_id = NodeId::new();
let transform_node = document_node_definitions::resolve_proto_node_type(graphene_std::transform_nodes::transform::IDENTIFIER)
.expect("Failed to create transform node")
.default_node_template();
responses.add(NodeGraphMessage::InsertNode {
node_id: transform_node_id,View on GitHub (pinned to c507b35645)
Solutions
- Grep the identifier's string value (e.g. "Spline") in document_node_definitions.rs and confirm a registration entry exists whose key exactly equals graphene_std::vector::spline::IDENTIFIER
- If the node was renamed or moved, update the IDENTIFIER constant or the registration key so both sides agree, then rebuild
- Replace .expect with let-else plus logging (and skip the spline insert) so a missing definition degrades instead of panicking the tool
- Add a test that resolves every tool-referenced IDENTIFIER (Spline, Transform, Combine Paths, Path) against DOCUMENT_NODE_TYPES, mirroring the existing registry test at document_node_definitions.rs:1559
Example fix
// before
let spline_node = document_node_definitions::resolve_proto_node_type(graphene_std::vector::spline::IDENTIFIER)
.expect("Failed to create Spline node")
.default_node_template();
// after
let Some(spline_node) = document_node_definitions::resolve_proto_node_type(graphene_std::vector::spline::IDENTIFIER) else {
log::error!("Spline node missing from DOCUMENT_NODE_TYPES; skipping spline merge step");
return;
};
let spline_node = spline_node.default_node_template(); Defensive patterns
Strategy: validation
Validate before calling
// Verify registry membership before the merge flow, not mid-merge:
fn can_merge_spline_layers() -> bool {
document_node_definitions::resolve_proto_node_type(graphene_std::vector::spline::IDENTIFIER).is_some()
&& document_node_definitions::resolve_proto_node_type(graphene_std::transform_nodes::transform::IDENTIFIER).is_some()
} Prevention
- Treat IDENTIFIER constants as the single source of truth; never inline string copies of node names at call sites
- Grep for the identifier string across the repo before renaming or removing any proto node
- Add a unit test resolving every tool-referenced identifier (Spline, Transform, Combine Paths, Path) against DOCUMENT_NODE_TYPES
- Remember node_template_input_override indexes template.inputs directly — keep override arrays length-aligned with the node's inputs
When it happens
Trigger: Invoking the merge flow with current_and_other_layer_is_spline == true (e.g. the Pen tool merging two spline-based layers) when graphene_std::vector::spline::IDENTIFIER has no matching entry in DOCUMENT_NODE_TYPES: the const was renamed, the Spline proto node was deleted or relocated, or the registration list was edited without re-adding it.
Common situations: Refactors that rename or move a node implementation without updating every tool-side IDENTIFIER reference; Graphite version upgrades where a proto node became a network node; cargo feature changes that conditionally register vector nodes; copy-paste of a sibling merge branch with a stale identifier.
Related errors
- Failed to create transform node
- Solidify Stroke node should exist
- Merge node
- Node
- Boolean node does not exist
AI-assisted analysis of GraphiteEditor/Graphite@c507b35645 (2026-08-16).
Data as JSON: /api/errors/0da324b6fa11dec0.
Report an issue: GitHub.