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
- Replace expect with if let Some(state) = shape_editor.selected_shape_state.get_mut(layer) so a missing entry simply skips deselection.
- Before the shrink branch, ensure the clicked layer has shape state: if !selected_shape_state.contains_key(layer), initialize it via select_connected first.
- 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.
- 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
- Never expect on map entries keyed by user-interaction-derived ids (clicked layers); use if-let.
- Keep stored_selection and selected_shape_state lifecycle in sync: clear both together on undo, deletion, and document switches.
- Add double-click interaction tests covering layers that were not previously selected.
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
- Cannot find connected anchor
- Star node can't be found
- Brush node does not exist
- Path node does not exist
- No min
AI-assisted analysis of GraphiteEditor/Graphite@c507b35645 (2026-08-16).
Data as JSON: /api/errors/8b74c44617eee934.
Report an issue: GitHub.