{"record":{"id":"c0c5fd686607d492","repo":"GraphiteEditor/Graphite","slug":"auto-tangents-node-does-not-exist","errorCode":null,"errorMessage":"Auto-Tangents node does not exist","messagePattern":"Auto-Tangents node does not exist","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"editor/src/messages/portfolio/document/graph_operation/utility_types.rs","lineNumber":134,"sourceCode":"\t\tself.network_interface.insert_node(morph_id, morph, &[]);\n\t\tself.network_interface.move_node_to_chain_start(&morph_id, layer, &[], self.import);\n\n\t\tmorph_id\n\t}\n\n\t/// Returns the Path node ID (the node closest to the layer's merge node in the chain).\n\tpub fn insert_control_path_data(&mut self, layer: LayerNodeIdentifier) -> NodeId {\n\t\t// Add Origins to Polyline node first (will be pushed deepest in the chain)\n\t\tlet origins_to_polyline = resolve_network_node_type(\"Origins to Polyline\")\n\t\t\t.expect(\"Origins to Polyline node does not exist\")\n\t\t\t.default_node_template();\n\t\tlet origins_to_polyline_id = NodeId::new();\n\t\tself.network_interface.insert_node(origins_to_polyline_id, origins_to_polyline, &[]);\n\t\tself.network_interface.move_node_to_chain_start(&origins_to_polyline_id, layer, &[], self.import);\n\n\t\t// Add Auto-Tangents node (between Origins to Polyline and Path), with spread=1 and preserve_existing=false\n\t\tlet auto_tangents = resolve_proto_node_type(graphene_std::vector::auto_tangents::IDENTIFIER)\n\t\t\t.expect(\"Auto-Tangents node does not exist\")\n\t\t\t.node_template_input_override([None, Some(NodeInput::value(TaggedValue::F64(1.), false)), Some(NodeInput::value(TaggedValue::Bool(false), false))]);\n\t\tlet auto_tangents_id = NodeId::new();\n\t\tself.network_interface.insert_node(auto_tangents_id, auto_tangents, &[]);\n\t\tself.network_interface.move_node_to_chain_start(&auto_tangents_id, layer, &[], self.import);\n\n\t\t// Add Path node to chain start (closest to the Merge node)\n\t\tlet path = resolve_network_node_type(\"Path\").expect(\"Path node does not exist\").default_node_template();\n\t\tlet path_id = NodeId::new();\n\t\tself.network_interface.insert_node(path_id, path, &[]);\n\t\tself.network_interface.move_node_to_chain_start(&path_id, layer, &[], self.import);\n\n\t\tpath_id\n\t}\n\n\tpub fn insert_vector(&mut self, subpaths: Vec<Subpath<PointId>>, layer: LayerNodeIdentifier, include_transform: bool, include_fill: bool, include_stroke: bool) {\n\t\t// Build a VectorModification that reproduces the geometry (same format the Pen tool uses)\n\t\tlet vector = Vector::from_subpaths(subpaths, true);\n\t\tlet modification = Box::new(VectorModification::create_from_vector(&vector));","sourceCodeStart":116,"sourceCodeEnd":152,"githubUrl":"https://github.com/GraphiteEditor/Graphite/blob/c507b356453361e31638b8bff8f6d46b6da2961e/editor/src/messages/portfolio/document/graph_operation/utility_types.rs#L116-L152","documentation":"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.","triggerScenarios":"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.","commonSituations":"Module reorganizations in graphene_std; renaming the Auto-Tangents node or its identifier constant; hand-maintained registry lists missing a newly added node.","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."],"exampleFix":"// before\nlet auto_tangents = resolve_proto_node_type(graphene_std::vector::auto_tangents::IDENTIFIER)\n    .expect(\"Auto-Tangents node does not exist\")\n    .node_template_input_override([...]);\n\n// after\nlet Some(at_def) = resolve_proto_node_type(graphene_std::vector::auto_tangents::IDENTIFIER) else {\n    log::error!(\"Auto-Tangents proto node not registered; aborting control path insert\");\n    return NodeId::new();\n};\nlet auto_tangents = at_def.node_template_input_override([...]);","handlingStrategy":"validation","validationCode":"// Before building a control path:\nif document_node_definitions::resolve_proto_node_type(graphene_std::vector::auto_tangents::IDENTIFIER).is_none() {\n    log::error!(\"Auto-Tangents node not registered; control path unavailable\");\n    return;\n}","typeGuard":"fn auto_tangents_registered() -> bool {\n    document_node_definitions::resolve_proto_node_type(graphene_std::vector::auto_tangents::IDENTIFIER).is_some()\n}","tryCatchPattern":"// Rust has no try/catch; handle the Option:\nlet Some(at_def) = resolve_proto_node_type(graphene_std::vector::auto_tangents::IDENTIFIER) else {\n    log::error!(\"Auto-Tangents missing\");\n    return;\n};","preventionTips":["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"],"tags":["rust","panic","expect","node-registry","proto-node","auto-tangents","control-path","graphite"],"backgroundTag":"node-definition-not-found","analyzedSha":"c507b356453361e31638b8bff8f6d46b6da2961e","analyzedAt":"2026-08-16T21:57:18.596Z","schemaVersion":2},"datasetVersion":"2026-08-16T23:17:17.608Z"}