{"record":{"id":"dc2fa25434710d16","repo":"GraphiteEditor/Graphite","slug":"cannot-find-state-for-layer","errorCode":null,"errorMessage":"Cannot find state for layer","messagePattern":"Cannot find state for layer","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"editor/src/messages/tool/common_functionality/shape_editor.rs","lineNumber":2289,"sourceCode":"\n\t\t\t\tlet segment_points = pathseg_points(segment);\n\n\t\t\t\t// Selecting handles\n\t\t\t\tfor (position, id) in [(segment_points.p1, ManipulatorPointId::PrimaryHandle(id)), (segment_points.p2, ManipulatorPointId::EndHandle(id))] {\n\t\t\t\t\tlet Some(position) = position else { continue };\n\t\t\t\t\tlet transformed_position = transform.transform_point2(position);\n\n\t\t\t\t\tlet select = match selection_shape {\n\t\t\t\t\t\tSelectionShape::Box(rect) => rect.contains(dvec2_to_point(transformed_position)),\n\t\t\t\t\t\tSelectionShape::Lasso(_) => polygon_subpath\n\t\t\t\t\t\t\t.as_ref()\n\t\t\t\t\t\t\t.expect(\"If `selection_shape` is a polygon then subpath is constructed beforehand.\")\n\t\t\t\t\t\t\t.contains_point(transformed_position),\n\t\t\t\t\t};\n\n\t\t\t\t\tif select && select_points {\n\t\t\t\t\t\tlet frontier_handles_for_layer = frontier_handles_info.and_then(|frontier_handles| frontier_handles.get(&layer));\n\t\t\t\t\t\tlet state = self.selected_shape_state.get(&layer).expect(\"Cannot find state for layer\");\n\t\t\t\t\t\tlet selected_segments_for_layer = selected_segments_for_layer(&vector, state);\n\t\t\t\t\t\tlet is_visible_handle = is_visible_point(id, &vector, path_overlay_mode, frontier_handles_for_layer, &selected_segments_for_layer, &selected_points);\n\n\t\t\t\t\t\tif is_visible_handle {\n\t\t\t\t\t\t\tpoints_inside.entry(layer).or_default().insert(id);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Checking for selection of anchor points\n\t\t\tfor (&id, &position) in vector.point_domain.ids().iter().zip(vector.point_domain.positions()) {\n\t\t\t\tlet transformed_position = transform.transform_point2(position);\n\n\t\t\t\tlet select = match selection_shape {\n\t\t\t\t\tSelectionShape::Box(rect) => rect.contains(dvec2_to_point(transformed_position)),\n\t\t\t\t\tSelectionShape::Lasso(_) => polygon_subpath\n\t\t\t\t\t\t.as_ref()","sourceCodeStart":2271,"sourceCodeEnd":2307,"githubUrl":"https://github.com/GraphiteEditor/Graphite/blob/c507b356453361e31638b8bff8f6d46b6da2961e/editor/src/messages/tool/common_functionality/shape_editor.rs#L2271-L2307","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\nlet state = self.selected_shape_state.get(&layer).expect(\"Cannot find state for layer\");\n// after\nlet Some(state) = self.selected_shape_state.get(&layer) else { continue };","handlingStrategy":"validation","validationCode":"// Same defensive form the sibling blocks already use (2148, 2166):\nlet Some(state) = self.selected_shape_state.get(&layer) else { continue };","typeGuard":null,"tryCatchPattern":null,"preventionTips":["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"],"tags":["rust","graphite","panic","expect","shape-editor","hashmap-lookup","borrow-checker","invariant"],"backgroundTag":"stale-selection-state","analyzedSha":"c507b356453361e31638b8bff8f6d46b6da2961e","analyzedAt":"2026-08-16T21:57:18.596Z","schemaVersion":2},"datasetVersion":"2026-08-16T23:17:17.608Z"}