iced-rs/iced · error
Stroke path
Error message
Stroke path
What it means
This panic occurs in the Iced wgpu backend when lyon's stroke tessellator fails to convert a transformed path's stroke outline into triangles. The library asserts success with .expect because stroke failure is treated as an internal invariant violation rather than a recoverable condition. It indicates the path geometry or stroke options produced an invalid tessellation (e.g. non-finite coordinates or an unsupported stroke configuration).
Solutions
- Validate the path's points and the transform matrix are finite before stroking (reject NaN/inf).
- Check the stroke width and options (line cap/join, miter limit) are sane positive values.
- If geometry comes from user input or external files, sanitize/simplify degenerate segments before building the Path.
- Update iced/lyon; some tessellation panics on edge-case geometry are fixed in newer releases.
- As a workaround, wrap rendering of untrusted geometry so a panic in a custom widget cannot take down the app, or rasterize it via a cache checked for validity first.
Example fix
// before
let path = path.transform(&self.transforms.current.0);
self.stroke_tessellator.tessellate_path(path.raw(), &options, buffer.as_mut()).expect("Stroke path");
// after (caller-side guard)
if path.bounds().is_valid() && transform.is_finite() {
frame.stroke(&path, stroke);
} Defensive patterns
Strategy: validation
Validate before calling
fn is_finite_path(p: &iced::widget::canvas::Path, t: &iced::Transformation) -> bool {
// all cached points and the transform must be finite before stroking
t.is_finite() // extend to iterate path points in custom geometry code
} Type guard
fn valid_transform(t: &iced::Transformation) -> bool {
let m = t.as_ref();
m.iter().all(|v| v.is_finite())
} Prevention
- Never build Paths from raw external data without NaN/inf checks.
- Clamp stroke width to a positive finite value.
- Guard animation interpolation so transforms never pass through singular/NaN states.
- Pin and update iced/lyon versions together.
When it happens
Trigger: Calling Stroke on a Path whose transformed points contain NaN/infinity (bad transform matrix or degenerate geometry), or with stroke options that lyon's CPU tessellator cannot process, inside geometry::Path::stroke with a non-rectangle/text path.
Common situations: Animatable transforms interpolating through singular/NaN matrices, paths built from external SVG data containing degenerate or zero-length segments, oversized stroke widths, or geometry passed through a custom widget that bypassed validation.
Understand the failure class
Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.
Related errors
AI-assisted analysis of iced-rs/iced@d146509d89 (2026-09-11).
Data as JSON: /api/errors/86e33d23e5494c68.
Report an issue: GitHub.
Appendix: source
Thrown at wgpu/src/geometry.rs:228
options.end_cap = into_line_cap(stroke.line_cap);
options.line_join = into_line_join(stroke.line_join);
let path = if stroke.line_dash.segments.is_empty() {
Cow::Borrowed(path)
} else {
Cow::Owned(dashed(path, stroke.line_dash))
};
if self.transforms.current.is_identity() {
self.stroke_tessellator
.tessellate_path(path.raw(), &options, buffer.as_mut())
} else {
let path = path.transform(&self.transforms.current.0);
self.stroke_tessellator
.tessellate_path(path.raw(), &options, buffer.as_mut())
}
.expect("Stroke path");
}
fn stroke_rectangle<'a>(&mut self, top_left: Point, size: Size, stroke: impl Into<Stroke<'a>>) {
let stroke = stroke.into();
let mut buffer = self
.buffers
.get_stroke(&self.transforms.current.transform_style(stroke.style));
let top_left = self
.transforms
.current
.0
.transform_point(lyon::math::Point::new(top_left.x, top_left.y));
let size = self
.transforms
.currentView on GitHub (pinned to d146509d89)