GraphiteEditor/Graphite · error
Transform node does not exist
Error message
Transform node does not exist
What it means
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.
Source
Thrown at editor/src/messages/portfolio/document/graph_operation/utility_types.rs:163
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));
let shape = resolve_network_node_type("Path")
.expect("Path node does not exist")
.node_template_input_override([None, Some(NodeInput::value(TaggedValue::VectorModification(modification), false))]);
let shape_id = NodeId::new();
self.network_interface.insert_node(shape_id, shape, &[]);
self.network_interface.move_node_to_chain_start(&shape_id, layer, &[], self.import);
if include_transform {
let transform = resolve_proto_node_type(graphene_std::transform_nodes::transform::IDENTIFIER)
.expect("Transform node does not exist")
.default_node_template();
let transform_id = NodeId::new();
self.network_interface.insert_node(transform_id, transform, &[]);
self.network_interface.move_node_to_chain_start(&transform_id, layer, &[], self.import);
}
if include_stroke {
let stroke = resolve_proto_node_type(graphene_std::vector_nodes::stroke::IDENTIFIER)
.expect("Stroke node does not exist")
.default_node_template();
let stroke_id = NodeId::new();
self.network_interface.insert_node(stroke_id, stroke, &[]);
self.network_interface.move_node_to_chain_start(&stroke_id, layer, &[], self.import);
}
if include_fill {
let fill = resolve_proto_node_type(graphene_std::vector_nodes::fill::IDENTIFIER)
.expect("Fill node does not exist")View on GitHub (pinned to c507b35645)
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.
Example fix
// before
let transform = resolve_proto_node_type(graphene_std::transform_nodes::transform::IDENTIFIER)
.expect("Transform node does not exist")
.default_node_template();
// after
if let Some(transform_def) = resolve_proto_node_type(graphene_std::transform_nodes::transform::IDENTIFIER) {
let transform = transform_def.default_node_template();
let transform_id = NodeId::new();
self.network_interface.insert_node(transform_id, transform, &[]);
self.network_interface.move_node_to_chain_start(&transform_id, layer, &[], self.import);
} else {
log::error!("Transform proto node not registered; inserting vector without transform node");
} Defensive patterns
Strategy: validation
Validate before calling
// Before inserting vector geometry with a transform:
if document_node_definitions::resolve_proto_node_type(graphene_std::transform_nodes::transform::IDENTIFIER).is_none() {
log::error!("Transform node not registered; inserting without transform");
} Type guard
fn transform_node_registered() -> bool {
document_node_definitions::resolve_proto_node_type(graphene_std::transform_nodes::transform::IDENTIFIER).is_some()
} Try / catch
// Rust has no try/catch; degrade to inserting without the transform node:
if let Some(def) = resolve_proto_node_type(graphene_std::transform_nodes::transform::IDENTIFIER) {
// insert transform node
} else {
log::error!("Transform missing; vector inserted without transform");
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: Reorganizing `transform_nodes`; renaming the Transform node or its identifier; registry entries dropped or feature-gated during refactors.
Related errors
- Stroke node does not exist
- Fill node does not exist
- Solidify Stroke node should exist
- Boolean node does not exist
- Morph node does not exist
AI-assisted analysis of GraphiteEditor/Graphite@c507b35645 (2026-08-16).
Data as JSON: /api/errors/13052d45b33e907d.
Report an issue: GitHub.