GraphiteEditor/Graphite · warning
Handle cannot be converted
Error message
Handle cannot be converted
What it means
During box/lasso point selection, points matching ManipulatorPointId::EndHandle(_) | ManipulatorPointId::PrimaryHandle(_) reach an arm that calls point.as_handle().expect("Handle cannot be converted") (shape_editor.rs:2155). as_handle (vector-types/src/vector/misc.rs:520-526) returns Some only for the two handle variants and None for Anchor, so the preceding match guard makes this expect unreachable today. It becomes live the moment someone widens the arm (e.g. to (_, _)) or adds a new ManipulatorPointId variant without updating this match — an Anchor would then return None and panic.
Source
Thrown at editor/src/messages/tool/common_functionality/shape_editor.rs:2155
select_segments,
select_points,
selection_mode,
);
if selection_change == SelectionChange::Clear {
self.deselect_all_points();
self.deselect_all_segments();
}
for (layer, points) in points_inside {
let Some(state) = self.selected_shape_state.get_mut(&layer) else { continue };
let Some(vector) = network_interface.compute_modified_vector(layer) else { continue };
for point in points {
match (point, selection_change) {
(_, SelectionChange::Shrink) => state.deselect_point(point),
(ManipulatorPointId::EndHandle(_) | ManipulatorPointId::PrimaryHandle(_), _) => {
let handle = point.as_handle().expect("Handle cannot be converted");
if handle.length(&vector) > 0. {
state.select_point(point);
}
}
(_, _) => state.select_point(point),
}
}
}
for (layer, segments) in segments_inside {
let Some(state) = self.selected_shape_state.get_mut(&layer) else { continue };
match selection_change {
SelectionChange::Shrink => segments.iter().for_each(|segment| state.deselect_segment(*segment)),
_ => segments.iter().for_each(|segment| state.select_segment(*segment)),
}
// Also select/deselect the endpoints of respective segments
let Some(vector) = network_interface.compute_modified_vector(layer) else { continue };View on GitHub (pinned to c507b35645)
Solutions
- Replace the expect with if let Some(handle) = point.as_handle() inside the arm
- Or match on point.as_handle() directly (Some(handle) => ..., None => fall through) so exhaustiveness is compiler-proven
- If keeping the expect, add a comment tying it to the match guard and a debug_assert on the discriminant
Example fix
// before
(ManipulatorPointId::EndHandle(_) | ManipulatorPointId::PrimaryHandle(_), _) => {
let handle = point.as_handle().expect("Handle cannot be converted");
if handle.length(&vector) > 0. { state.select_point(point); }
}
// after
(ManipulatorPointId::EndHandle(_) | ManipulatorPointId::PrimaryHandle(_), _) => {
if let Some(handle) = point.as_handle() {
if handle.length(&vector) > 0. { state.select_point(point); }
}
} Defensive patterns
Strategy: type-guard
Type guard
// Compiler-proven narrowing instead of expect:
match point.as_handle() {
Some(handle) if handle.length(&vector) > 0. => state.select_point(point),
_ => state.select_point(point), // anchors and zero-length handles
} Prevention
- Prefer pattern-matching on as_handle()/as_anchor() over expect guarded by a separate match arm
- When adding a ManipulatorPointId variant, grep for as_handle()/as_anchor() expects and revisit each guard
- Keep match arms narrow: (EndHandle|PrimaryHandle, _) must stay coupled to the as_handle() call inside it
When it happens
Trigger: Regression edits: widening the match arm to cover Anchor points, adding a new ManipulatorPointId variant, or reordering arms so a non-handle point reaches the expect during a box/lasso selection drag.
Common situations: Copy-paste of the arm into a new match without the guard; enum extensions during feature work on manipulators; refactors that replace the match with an if that loses the narrowing.
Related errors
- If `selection_shape` is a polygon then subpath is constructe
- Cannot find state for layer
- 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/b573cc6d1a117cc4.
Report an issue: GitHub.