GraphiteEditor/Graphite · error
Auto-Tangents node does not exist
Error message
Auto-Tangents node does not exist
What it means
Panics when `resolve_proto_node_type(graphene_std::vector::auto_tangents::IDENTIFIER)` returns `None` in `insert_control_path_data`, which inserts an Auto-Tangents node (spread=1, preserve_existing=false) between Origins to Polyline and Path. The proto-node definition must be present in the static `DOCUMENT_NODE_TYPES` registry; the expect guards the registry/IDENTIFIER invariant.
Source
Thrown at editor/src/messages/portfolio/document/graph_operation/utility_types.rs:134
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);
// Add Auto-Tangents node (between Origins to Polyline and Path), with spread=1 and preserve_existing=false
let auto_tangents = resolve_proto_node_type(graphene_std::vector::auto_tangents::IDENTIFIER)
.expect("Auto-Tangents node does not exist")
.node_template_input_override([None, Some(NodeInput::value(TaggedValue::F64(1.), false)), Some(NodeInput::value(TaggedValue::Bool(false), false))]);
let auto_tangents_id = NodeId::new();
self.network_interface.insert_node(auto_tangents_id, auto_tangents, &[]);
self.network_interface.move_node_to_chain_start(&auto_tangents_id, layer, &[], self.import);
// Add Path node to chain start (closest to the Merge node)
let path = resolve_network_node_type("Path").expect("Path node does not exist").default_node_template();
let path_id = NodeId::new();
self.network_interface.insert_node(path_id, path, &[]);
self.network_interface.move_node_to_chain_start(&path_id, layer, &[], self.import);
path_id
}
pub fn insert_vector(&mut self, subpaths: Vec<Subpath<PointId>>, layer: LayerNodeIdentifier, include_transform: bool, include_fill: bool, include_stroke: bool) {
// Build a VectorModification that reproduces the geometry (same format the Pen tool uses)
let vector = Vector::from_subpaths(subpaths, true);
let modification = Box::new(VectorModification::create_from_vector(&vector));View on GitHub (pinned to c507b35645)
Solutions
- Verify a registry entry exists whose identifier equals `graphene_std::vector::auto_tangents::IDENTIFIER`.
- Repair the drift: restore the IDENTIFIER or re-add the definition entry.
- Handle `None` with a logged early return so the chain insert aborts cleanly instead of panicking.
- Include this identifier in an automated registry-completeness check.
Example fix
// before
let auto_tangents = resolve_proto_node_type(graphene_std::vector::auto_tangents::IDENTIFIER)
.expect("Auto-Tangents node does not exist")
.node_template_input_override([...]);
// after
let Some(at_def) = resolve_proto_node_type(graphene_std::vector::auto_tangents::IDENTIFIER) else {
log::error!("Auto-Tangents proto node not registered; aborting control path insert");
return NodeId::new();
};
let auto_tangents = at_def.node_template_input_override([...]); Defensive patterns
Strategy: validation
Validate before calling
// Before building a control path:
if document_node_definitions::resolve_proto_node_type(graphene_std::vector::auto_tangents::IDENTIFIER).is_none() {
log::error!("Auto-Tangents node not registered; control path unavailable");
return;
} Type guard
fn auto_tangents_registered() -> bool {
document_node_definitions::resolve_proto_node_type(graphene_std::vector::auto_tangents::IDENTIFIER).is_some()
} Try / catch
// Rust has no try/catch; handle the Option:
let Some(at_def) = resolve_proto_node_type(graphene_std::vector::auto_tangents::IDENTIFIER) else {
log::error!("Auto-Tangents missing");
return;
}; Prevention
- Include auto_tangents in registry-completeness tests
- Synchronize renames across graphene_std and document_node_definitions.rs
- Use let-else in chain-building helpers
- Register new vector nodes with their editor definitions in one commit
When it happens
Trigger: Creating a control path for a layer via `insert_control_path_data`. Fires when the `auto_tangents` IDENTIFIER resolves to no registry entry — the node moved out of `graphene_std::vector`, its IDENTIFIER changed, or the definition was never registered.
Common situations: Module reorganizations in graphene_std; renaming the Auto-Tangents node or its identifier constant; hand-maintained registry lists missing a newly added node.
Related errors
- Solidify Stroke node should exist
- Boolean node does not exist
- Morph node does not exist
- Origins to Polyline node does not exist
- Path node does not exist
AI-assisted analysis of GraphiteEditor/Graphite@c507b35645 (2026-08-16).
Data as JSON: /api/errors/c0c5fd686607d492.
Report an issue: GitHub.