GraphiteEditor/Graphite · error
Morph node does not exist
Error message
Morph node does not exist
What it means
Panics when `resolve_proto_node_type(graphene_std::vector::morph::IDENTIFIER)` returns `None` in `insert_morph_data`. The Morph proto node (interpolating between two shapes at 0.5) is inserted at a layer's chain start; its definition must be registered in the static `DOCUMENT_NODE_TYPES` registry under the `morph` IDENTIFIER. The expect is a compile-time-style invariant against registry/identifier drift.
Source
Thrown at editor/src/messages/portfolio/document/graph_operation/utility_types.rs:112
self.network_interface.insert_node(boolean_id, boolean, &[]);
self.network_interface.move_node_to_chain_start(&boolean_id, layer, &[], self.import);
}
pub fn insert_blend_data(&mut self, layer: LayerNodeIdentifier, count: f64) -> NodeId {
let blend = resolve_network_node_type("Blend")
.expect("Blend node does not exist")
.node_template_input_override([Some(NodeInput::type_default(list!(Graphic), true)), Some(NodeInput::value(TaggedValue::F64(count), false))]);
let blend_id = NodeId::new();
self.network_interface.insert_node(blend_id, blend, &[]);
self.network_interface.move_node_to_chain_start(&blend_id, layer, &[], self.import);
blend_id
}
pub fn insert_morph_data(&mut self, layer: LayerNodeIdentifier) -> NodeId {
let morph = resolve_proto_node_type(graphene_std::vector::morph::IDENTIFIER)
.expect("Morph node does not exist")
.node_template_input_override([Some(NodeInput::type_default(list!(Graphic), true)), Some(NodeInput::value(TaggedValue::F64(0.5), false))]);
let morph_id = NodeId::new();
self.network_interface.insert_node(morph_id, morph, &[]);
self.network_interface.move_node_to_chain_start(&morph_id, layer, &[], self.import);
morph_id
}
/// Returns the Path node ID (the node closest to the layer's merge node in the chain).
pub fn insert_control_path_data(&mut self, layer: LayerNodeIdentifier) -> NodeId {
// Add Origins to Polyline node first (will be pushed deepest in the chain)
let origins_to_polyline = resolve_network_node_type("Origins to Polyline")
.expect("Origins to Polyline node does not exist")
.default_node_template();
let origins_to_polyline_id = NodeId::new();
self.network_interface.insert_node(origins_to_polyline_id, origins_to_polyline, &[]);
self.network_interface.move_node_to_chain_start(&origins_to_polyline_id, layer, &[], self.import);View on GitHub (pinned to c507b35645)
Solutions
- Confirm the registry contains a definition whose identifier equals `graphene_std::vector::morph::IDENTIFIER`.
- Fix whichever side drifted: restore the IDENTIFIER value or update the registry entry.
- Handle `None`: log `"Morph proto node not registered"` and bail out before mutating the layer chain.
- Cover this identifier in a registry-completeness unit test.
Example fix
// before
let morph = resolve_proto_node_type(graphene_std::vector::morph::IDENTIFIER)
.expect("Morph node does not exist")
.node_template_input_override([...]);
// after
let Some(morph_def) = resolve_proto_node_type(graphene_std::vector::morph::IDENTIFIER) else {
log::error!("Morph proto node not registered; skipping morph insert");
return NodeId::new(); // or return Option<NodeId> and propagate
};
let morph = morph_def.node_template_input_override([...]); Defensive patterns
Strategy: validation
Validate before calling
// Before the morph operation:
if document_node_definitions::resolve_proto_node_type(graphene_std::vector::morph::IDENTIFIER).is_none() {
log::error!("Morph node not registered; command unavailable");
return;
} Type guard
fn morph_node_registered() -> bool {
document_node_definitions::resolve_proto_node_type(graphene_std::vector::morph::IDENTIFIER).is_some()
} Try / catch
// Rust has no try/catch; handle the Option:
let Some(morph_def) = resolve_proto_node_type(graphene_std::vector::morph::IDENTIFIER) else {
log::error!("Morph node missing");
return;
}; Prevention
- Keep IDENTIFIER constants as the single source of truth shared with registry tests
- Cover morph in registry-change test matrices
- Avoid expect in helpers that mutate the node graph
- Register definitions atomically with node additions
When it happens
Trigger: Applying the Morph operation to layers (calls `insert_morph_data`, which hardcodes morph amount 0.5). Fires only if `graphene_std::vector::morph::IDENTIFIER` is absent from the registry — module moved, IDENTIFIER renamed, or definition entry removed/not added.
Common situations: Renaming the morph node or changing its `IDENTIFIER` constant without updating the registry; moving morph out of `graphene_std::vector`; new-node registration omissions when the registry list is maintained by hand.
Related errors
- Solidify Stroke node should exist
- Boolean node does not exist
- Auto-Tangents node does not exist
- Transform node does not exist
- Stroke node does not exist
AI-assisted analysis of GraphiteEditor/Graphite@c507b35645 (2026-08-16).
Data as JSON: /api/errors/e2e54c76638f2ede.
Report an issue: GitHub.