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

  1. Validate the path's points and the transform matrix are finite before stroking (reject NaN/inf).
  2. Check the stroke width and options (line cap/join, miter limit) are sane positive values.
  3. If geometry comes from user input or external files, sanitize/simplify degenerate segments before building the Path.
  4. Update iced/lyon; some tessellation panics on edge-case geometry are fixed in newer releases.
  5. 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

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
            .current

View on GitHub (pinned to d146509d89)