GraphiteEditor/Graphite · error

Path node does not exist

Error message

Path node does not exist

What it means

Panics when `resolve_network_node_type("Path")` returns `None` at the end of `insert_control_path_data` (the Path node is added chain-start, closest to the layer's Merge node). The `"Path"` network-node definition must exist in the static registry; this expect asserts its presence. Because Path is one of the most fundamental node types, hitting this panic indicates wholesale registry breakage rather than an isolated rename.

Source

Thrown at editor/src/messages/portfolio/document/graph_operation/utility_types.rs:141

	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));

		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);

View on GitHub (pinned to c507b35645)

Solutions

  1. Check that `"Path"` exists in `DOCUMENT_NODE_TYPES`; restore the entry if missing.
  2. Align the string with the registry key if the node was renamed (and audit the other `"Path"` call sites in this file).
  3. Replace the expect with logged `Option` handling, aborting the control-path insert on `None`.
  4. Add a smoke test that resolves every bare string used in `utility_types.rs`.

Example fix

// before
let path = resolve_network_node_type("Path").expect("Path node does not exist").default_node_template();

// after
let Some(path_def) = resolve_network_node_type("Path") else {
    log::error!("Path node definition not registered; aborting control path insert");
    return NodeId::new();
};
let path = path_def.default_node_template();
Defensive patterns

Strategy: validation

Validate before calling

// Before building a control path:
if document_node_definitions::resolve_network_node_type("Path").is_none() {
    log::error!("Path node not registered; control path unavailable");
    return;
}

Type guard

fn path_node_available() -> bool {
    document_node_definitions::resolve_network_node_type("Path").is_some()
}

Try / catch

// Rust has no try/catch; branch on the Option:
let Some(path_def) = resolve_network_node_type("Path") else {
    log::error!("Path node missing");
    return;
};

Prevention

When it happens

Trigger: Creating a control path for a layer. Fires when the `"Path"` key is missing from `DOCUMENT_NODE_TYPES` — e.g. the registry-generation macro broke, the entry was renamed, or a build config excluded core definitions.

Common situations: Major refactors of `document_node_definitions.rs`; rebase conflicts that silently drop entries; typos when the key string is duplicated at many call sites (this is one of several `"Path"` lookups in the file).

Related errors


AI-assisted analysis of GraphiteEditor/Graphite@c507b35645 (2026-08-16). Data as JSON: /api/errors/1e1a65c4a4b99b1b. Report an issue: GitHub.