GraphiteEditor/Graphite · error

No state for selected layer

Error message

No state for selected layer

What it means

During a double-click on a layer in the path tool with shrink_selection, the code restores the stored multi-selection and then fetches that layer's per-layer editing state with selected_shape_state.get_mut(layer).expect("No state for selected layer"). The map only contains layers that were previously selected as editable shapes, so the expect fires when the double-clicked layer has no entry — the shape editor's selection state and the layer being clicked have desynced (e.g., the layer was never added via select_connected, or the restored stored_selection lacks it). This is a state-machine desync inside the tool, not a registry issue.

Source

Thrown at editor/src/messages/tool/tool_messages/path_tool.rs:3082

					if shape_editor.is_selected_layer(*layer) {
						if extend_selection && !tool_data.first_selected_with_single_click {
							responses.add(NodeGraphMessage::SelectedNodesRemove { nodes: vec![layer.to_node()] });

							if let Some(selection) = &tool_data.stored_selection {
								let mut selection = selection.clone();
								selection.remove(layer);
								shape_editor.selected_shape_state = selection;
								tool_data.stored_selection = None;
							}
						} else if shrink_selection && !tool_data.first_selected_with_single_click {
							// Only deselect all the points of the double clicked layer
							if let Some(selection) = &tool_data.stored_selection {
								let selection = selection.clone();
								shape_editor.selected_shape_state = selection;
								tool_data.stored_selection = None;
							}

							let state = shape_editor.selected_shape_state.get_mut(layer).expect("No state for selected layer");
							state.deselect_all_points_in_layer();
							state.deselect_all_segments_in_layer();
						} else if !tool_data.first_selected_with_single_click {
							// Select according to the selected editing mode
							let point_editing_mode = tool_options.path_editing_mode.point_editing_mode;
							let segment_editing_mode = tool_options.path_editing_mode.segment_editing_mode;
							shape_editor.select_connected(document, *layer, input.mouse.position, point_editing_mode, segment_editing_mode);

							// Select all the other layers back again
							if let Some(selection) = &tool_data.stored_selection {
								let mut selection = selection.clone();
								selection.remove(layer);

								for (layer, state) in selection {
									shape_editor.selected_shape_state.insert(layer, state);
								}
								tool_data.stored_selection = None;
							}

View on GitHub (pinned to c507b35645)

Solutions

  1. Replace expect with if let Some(state) = shape_editor.selected_shape_state.get_mut(layer) so a missing entry simply skips deselection.
  2. Before the shrink branch, ensure the clicked layer has shape state: if !selected_shape_state.contains_key(layer), initialize it via select_connected first.
  3. Clear tool_data.stored_selection whenever the shape editor's selected_shape_state changes structure (deletions, undo) so a restore never injects a stale map.
  4. Write a unit/integration test that double-clicks an unselected layer with shrink_selection to lock the guarded behavior.

Example fix

// before
let state = shape_editor.selected_shape_state.get_mut(layer).expect("No state for selected layer");
state.deselect_all_points_in_layer();
state.deselect_all_segments_in_layer();

// after
if let Some(state) = shape_editor.selected_shape_state.get_mut(layer) {
	state.deselect_all_points_in_layer();
	state.deselect_all_segments_in_layer();
} else {
	log::warn!("path tool: no shape state for layer {layer:?} during shrink selection");
}
Defensive patterns

Strategy: validation

Validate before calling

if shape_editor.selected_shape_state.contains_key(layer) {
	let state = shape_editor.selected_shape_state.get_mut(layer).unwrap();
	state.deselect_all_points_in_layer();
	state.deselect_all_segments_in_layer();
} else {
	// layer never selected as editable shape: nothing to shrink
}

Type guard

fn has_shape_state(shape_editor: &ShapeState, layer: LayerNodeIdentifier) -> bool {
	shape_editor.selected_shape_state.contains_key(&layer)
}

Prevention

When it happens

Trigger: Double-clicking a path layer while shrink_selection is true and first_selected_with_single_click is false: the branch restores tool_data.stored_selection into shape_editor.selected_shape_state and immediately calls get_mut(layer); if that layer was not part of the shape selection state (first click selected a different layer, or selection was cleared), the expect panics.

Common situations: Rapid double-clicks across different layers where the second click lands on a layer never added by select_connected; undo between clicks resetting shape state but not stored_selection; layers whose shape state was removed by a selection-removal branch just above this code (the same function removes the layer from the map in the first branch); stale stored_selection after document mutations delete and recreate layers.

Related errors


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