GraphiteEditor/Graphite · warning

Cannot find state for layer

Error message

Cannot find state for layer

What it means

Inside the per-layer loop of select_intersecting_points (for &layer in self.selected_shape_state.keys(), shape_editor.rs:2209), the handle-visibility block refetches state with self.selected_shape_state.get(&layer).expect("Cannot find state for layer") (2289). Since layer is copied from that same map and nothing removes entries during the loop, the expect cannot fail in the current code — it exists to project a reference past the immutable borrow of keys(). Sibling blocks in the same function (2148, 2166) use the defensive `let Some(state) = ... else { continue }` form instead, so this site is an inconsistency that becomes a real panic only under refactor.

Source

Thrown at editor/src/messages/tool/common_functionality/shape_editor.rs:2289

				let segment_points = pathseg_points(segment);

				// Selecting handles
				for (position, id) in [(segment_points.p1, ManipulatorPointId::PrimaryHandle(id)), (segment_points.p2, ManipulatorPointId::EndHandle(id))] {
					let Some(position) = position else { continue };
					let transformed_position = transform.transform_point2(position);

					let select = match selection_shape {
						SelectionShape::Box(rect) => rect.contains(dvec2_to_point(transformed_position)),
						SelectionShape::Lasso(_) => polygon_subpath
							.as_ref()
							.expect("If `selection_shape` is a polygon then subpath is constructed beforehand.")
							.contains_point(transformed_position),
					};

					if select && select_points {
						let frontier_handles_for_layer = frontier_handles_info.and_then(|frontier_handles| frontier_handles.get(&layer));
						let state = self.selected_shape_state.get(&layer).expect("Cannot find state for layer");
						let selected_segments_for_layer = selected_segments_for_layer(&vector, state);
						let is_visible_handle = is_visible_point(id, &vector, path_overlay_mode, frontier_handles_for_layer, &selected_segments_for_layer, &selected_points);

						if is_visible_handle {
							points_inside.entry(layer).or_default().insert(id);
						}
					}
				}
			}

			// Checking for selection of anchor points
			for (&id, &position) in vector.point_domain.ids().iter().zip(vector.point_domain.positions()) {
				let transformed_position = transform.transform_point2(position);

				let select = match selection_shape {
					SelectionShape::Box(rect) => rect.contains(dvec2_to_point(transformed_position)),
					SelectionShape::Lasso(_) => polygon_subpath
						.as_ref()

View on GitHub (pinned to c507b35645)

Solutions

  1. Mirror the defensive pattern already used at 2148/2166: let Some(state) = self.selected_shape_state.get(&layer) else { continue }
  2. If mutation during iteration is required, collect the layer ids into a Vec before the loop and re-lookup each iteration
  3. Keep per-layer state mutation out of select_intersecting_points; stage it via points_inside/segments_inside as the function already does

Example fix

// before
let state = self.selected_shape_state.get(&layer).expect("Cannot find state for layer");
// after
let Some(state) = self.selected_shape_state.get(&layer) else { continue };
Defensive patterns

Strategy: validation

Validate before calling

// Same defensive form the sibling blocks already use (2148, 2166):
let Some(state) = self.selected_shape_state.get(&layer) else { continue };

Prevention

When it happens

Trigger: Refactors that mutate selected_shape_state (retain/remove/insert) inside the iteration, or that move the 2289 lookup after code paths capable of deleting a layer's state entry mid-loop.

Common situations: Feature work that deselects layers as a side effect of lasso selection; extracting the loop body into a method that takes &mut self; changing the iteration to run over a stale snapshot of layer ids.

Related errors


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