{"record":{"id":"13052d45b33e907d","repo":"GraphiteEditor/Graphite","slug":"transform-node-does-not-exist","errorCode":null,"errorMessage":"Transform node does not exist","messagePattern":"Transform node does not exist","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"editor/src/messages/portfolio/document/graph_operation/utility_types.rs","lineNumber":163,"sourceCode":"\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));\n\n\t\tlet shape = resolve_network_node_type(\"Path\")\n\t\t\t.expect(\"Path node does not exist\")\n\t\t\t.node_template_input_override([None, Some(NodeInput::value(TaggedValue::VectorModification(modification), false))]);\n\t\tlet shape_id = NodeId::new();\n\t\tself.network_interface.insert_node(shape_id, shape, &[]);\n\t\tself.network_interface.move_node_to_chain_start(&shape_id, layer, &[], self.import);\n\n\t\tif include_transform {\n\t\t\tlet transform = resolve_proto_node_type(graphene_std::transform_nodes::transform::IDENTIFIER)\n\t\t\t\t.expect(\"Transform node does not exist\")\n\t\t\t\t.default_node_template();\n\t\t\tlet transform_id = NodeId::new();\n\t\t\tself.network_interface.insert_node(transform_id, transform, &[]);\n\t\t\tself.network_interface.move_node_to_chain_start(&transform_id, layer, &[], self.import);\n\t\t}\n\n\t\tif include_stroke {\n\t\t\tlet stroke = resolve_proto_node_type(graphene_std::vector_nodes::stroke::IDENTIFIER)\n\t\t\t\t.expect(\"Stroke node does not exist\")\n\t\t\t\t.default_node_template();\n\t\t\tlet stroke_id = NodeId::new();\n\t\t\tself.network_interface.insert_node(stroke_id, stroke, &[]);\n\t\t\tself.network_interface.move_node_to_chain_start(&stroke_id, layer, &[], self.import);\n\t\t}\n\n\t\tif include_fill {\n\t\t\tlet fill = resolve_proto_node_type(graphene_std::vector_nodes::fill::IDENTIFIER)\n\t\t\t\t.expect(\"Fill node does not exist\")","sourceCodeStart":145,"sourceCodeEnd":181,"githubUrl":"https://github.com/GraphiteEditor/Graphite/blob/c507b356453361e31638b8bff8f6d46b6da2961e/editor/src/messages/portfolio/document/graph_operation/utility_types.rs#L145-L181","documentation":"Panics when `resolve_proto_node_type(graphene_std::transform_nodes::transform::IDENTIFIER)` returns `None` in `insert_vector` (only when `include_transform` is true), used to attach a Transform node to freshly inserted vector geometry. The proto-node definition must be registered in the static `DOCUMENT_NODE_TYPES` registry; the expect is a registry-drift tripwire.","triggerScenarios":"Inserting vector geometry that carries its own transform (e.g. pasting transformed shapes). Fires when the `transform` IDENTIFIER from `graphene_std::transform_nodes` is not in the registry — module move, IDENTIFIER change, or missing definition entry.","commonSituations":"Reorganizing `transform_nodes`; renaming the Transform node or its identifier; registry entries dropped or feature-gated during refactors.","solutions":["Confirm the registry resolves `graphene_std::transform_nodes::transform::IDENTIFIER`.","Repair whichever side drifted (IDENTIFIER constant vs registry entry).","Handle `None` by logging and skipping only the transform insertion (geometry can still be inserted without its own transform node).","Add the identifier to a registry-completeness test."],"exampleFix":"// before\nlet transform = resolve_proto_node_type(graphene_std::transform_nodes::transform::IDENTIFIER)\n    .expect(\"Transform node does not exist\")\n    .default_node_template();\n\n// after\nif let Some(transform_def) = resolve_proto_node_type(graphene_std::transform_nodes::transform::IDENTIFIER) {\n    let transform = transform_def.default_node_template();\n    let transform_id = NodeId::new();\n    self.network_interface.insert_node(transform_id, transform, &[]);\n    self.network_interface.move_node_to_chain_start(&transform_id, layer, &[], self.import);\n} else {\n    log::error!(\"Transform proto node not registered; inserting vector without transform node\");\n}","handlingStrategy":"validation","validationCode":"// Before inserting vector geometry with a transform:\nif document_node_definitions::resolve_proto_node_type(graphene_std::transform_nodes::transform::IDENTIFIER).is_none() {\n    log::error!(\"Transform node not registered; inserting without transform\");\n}","typeGuard":"fn transform_node_registered() -> bool {\n    document_node_definitions::resolve_proto_node_type(graphene_std::transform_nodes::transform::IDENTIFIER).is_some()\n}","tryCatchPattern":"// Rust has no try/catch; degrade to inserting without the transform node:\nif let Some(def) = resolve_proto_node_type(graphene_std::transform_nodes::transform::IDENTIFIER) {\n    // insert transform node\n} else {\n    log::error!(\"Transform missing; vector inserted without transform\");\n}","preventionTips":["Include transform_nodes identifiers in registry tests","Make optional chain nodes (transform/stroke/fill) genuinely optional in code, not just in flags","Register definitions atomically with node moves","Use let-else instead of expect"],"tags":["rust","panic","expect","node-registry","proto-node","transform-node","vector-insert","graphite"],"backgroundTag":"node-definition-not-found","analyzedSha":"c507b356453361e31638b8bff8f6d46b6da2961e","analyzedAt":"2026-08-16T21:57:18.596Z","schemaVersion":2},"datasetVersion":"2026-08-16T23:17:17.608Z"}