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
- Mirror the defensive pattern already used at 2148/2166: let Some(state) = self.selected_shape_state.get(&layer) else { continue }
- If mutation during iteration is required, collect the layer ids into a Vec before the loop and re-lookup each iteration
- 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
- Use let-else + continue for map lookups inside iteration, even when currently infallible
- Never mutate selected_shape_state while iterating its keys; collect the keys first
- During refactors, replace expect-with-comment with the codebase's dominant defensive pattern to avoid mixed conventions
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
- Handle cannot be converted
- If `selection_shape` is a polygon then subpath is constructe
- In `check_layer()`: there should be a `target`
- No anchor position for handle
- No handle position
AI-assisted analysis of GraphiteEditor/Graphite@c507b35645 (2026-08-16).
Data as JSON: /api/errors/dc2fa25434710d16.
Report an issue: GitHub.