GraphiteEditor/Graphite · error

Origins to Polyline node does not exist

Error message

Origins to Polyline node does not exist

What it means

Panics when the string lookup `resolve_network_node_type("Origins to Polyline")` returns `None` inside `insert_control_path_data`. This helper builds a `Origins to Polyline -> Auto-Tangents -> Path` chain when constructing a control path for a layer; the definition must exist in `DOCUMENT_NODE_TYPES` under the exact key `"Origins to Polyline"`. The expect is a static registry-presence assertion.

Source

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

	}

	pub fn insert_morph_data(&mut self, layer: LayerNodeIdentifier) -> NodeId {
		let morph = resolve_proto_node_type(graphene_std::vector::morph::IDENTIFIER)
			.expect("Morph node does not exist")
			.node_template_input_override([Some(NodeInput::type_default(list!(Graphic), true)), Some(NodeInput::value(TaggedValue::F64(0.5), false))]);

		let morph_id = NodeId::new();
		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);

View on GitHub (pinned to c507b35645)

Solutions

  1. Grep `DOCUMENT_NODE_TYPES` for the exact string `"Origins to Polyline"`; re-add or fix the key if absent/renamed.
  2. If the node was renamed, update this call site or register an alias.
  3. Convert the `expect` into `Option` handling that logs and returns before inserting nodes.
  4. Prefer proto-node IDENTIFIER constants over display-name strings where possible.

Example fix

// before
let origins_to_polyline = resolve_network_node_type("Origins to Polyline")
    .expect("Origins to Polyline node does not exist")
    .default_node_template();

// after
let Some(otp_def) = resolve_network_node_type("Origins to Polyline") else {
    log::error!("Origins to Polyline node not registered; aborting control path insert");
    return NodeId::new();
};
let origins_to_polyline = otp_def.default_node_template();
Defensive patterns

Strategy: validation

Validate before calling

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

Type guard

fn origins_to_polyline_available() -> bool {
    document_node_definitions::resolve_network_node_type("Origins to Polyline").is_some()
}

Try / catch

// Rust has no try/catch; branch on the Option:
let Some(otp_def) = resolve_network_node_type("Origins to Polyline") else {
    log::error!("Origins to Polyline missing");
    return;
};

Prevention

When it happens

Trigger: Any tool path that creates a control path (e.g. momentum/origin-based path editing flows) calls `insert_control_path_data`. Fires when the `"Origins to Polyline"` key is missing — renamed display name, dropped registry entry, or typo in the string.

Common situations: Display-name-driven refactors (this lookup keys on a human-readable name containing spaces, so it is especially typo-prone); rebase drops; renaming the node in the properties panel without an alias.

Related errors


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