{"record":{"id":"5955a9ffec577cac","repo":"iced-rs/iced","slug":"create-color","errorCode":null,"errorMessage":"Create color","messagePattern":"Create color","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"tiny_skia/src/engine.rs","lineNumber":154,"sourceCode":"                shader: match background {\n                    Background::Color(color) => tiny_skia::Shader::SolidColor(into_color(*color)),\n                    Background::Gradient(Gradient::Linear(linear)) => {\n                        let (start, end) = quad.bounds.chord(linear.angle);\n\n                        let stops: Vec<tiny_skia::GradientStop> = linear\n                            .stops\n                            .into_iter()\n                            .flatten()\n                            .map(|stop| {\n                                tiny_skia::GradientStop::new(\n                                    stop.offset,\n                                    tiny_skia::Color::from_rgba(\n                                        stop.color.b,\n                                        stop.color.g,\n                                        stop.color.r,\n                                        stop.color.a,\n                                    )\n                                    .expect(\"Create color\"),\n                                )\n                            })\n                            .collect();\n\n                        tiny_skia::LinearGradient::new(\n                            tiny_skia::Point {\n                                x: start.x,\n                                y: start.y,\n                            },\n                            tiny_skia::Point { x: end.x, y: end.y },\n                            if stops.is_empty() {\n                                vec![tiny_skia::GradientStop::new(0.0, tiny_skia::Color::BLACK)]\n                            } else {\n                                stops\n                            },\n                            tiny_skia::SpreadMode::Pad,\n                            tiny_skia::Transform::identity(),\n                        )","sourceCodeStart":136,"sourceCodeEnd":172,"githubUrl":"https://github.com/iced-rs/iced/blob/3de451447bd28217bb535632867550908e29d5d0/tiny_skia/src/engine.rs#L136-L172","documentation":"tiny_skia::Color::from_rgba returns None when any component is NaN (out-of-range floats are tolerated; NaN is not). While converting iced gradient stops into tiny-skia gradient stops, the tiny_skia engine unwraps that result with .expect(\"Create color\") (tiny_skia/src/engine.rs:154), so a NaN in any channel (r, g, b, a) of any gradient stop panics during drawing.","triggerScenarios":"Drawing a gradient (linear/radial fills) whose stop colors contain NaN - typically 0.0/0.0 or inf - inf from interpolation code (lerp with an out-of-domain t, division by zero when normalizing), or animated colors computed from uninitialized/invalid state.","commonSituations":"Color interpolation/animation helpers that divide without guarding zero denominators; gradients generated from data (heatmaps) with degenerate values; themes parsed from bad numeric input; NaN sneaking in through serialization.","solutions":["Sanitize stop colors before building gradients: replace non-finite components (check f32::is_finite) with defaults and clamp to 0..=1","Trace the math that produced the stop color - usually a division by zero in interpolation or normalization","Use from_rgba8 or integer inputs for fixed palettes so NaN cannot occur","Add a debug_assert! when computing animated colors so bad values surface with context"],"exampleFix":"// before\nlet g = t / weight; // weight == 0.0 -> NaN -> panic in renderer\nstops.push(GradientStop::new(t, Color::from_rgba(t, g, 1.0 - t, 1.0)));\n\n// after\nfn safe_color(r: f32, g: f32, b: f32, a: f32) -> Color {\n    let fix = |v: f32, d: f32| if v.is_finite() { v.clamp(0.0, 1.0) } else { d };\n    Color::from_rgba(fix(r, 0.0), fix(g, 0.0), fix(b, 0.0), fix(a, 1.0))\n}\nstops.push(GradientStop::new(t, safe_color(t, t / weight.max(f32::EPSILON), 1.0 - t, 1.0)));","handlingStrategy":"validation","validationCode":"fn safe_color(r: f32, g: f32, b: f32, a: f32) -> Color {\n    let fix = |v: f32, d: f32| if v.is_finite() { v.clamp(0.0, 1.0) } else { d };\n    Color::from_rgba(fix(r, 0.0), fix(g, 0.0), fix(b, 0.0), fix(a, 1.0))\n}\n// validate stops before building a gradient\nfor stop in &stops {\n    debug_assert!([stop.color.r, stop.color.g, stop.color.b, stop.color.a]\n        .iter().all(|c| c.is_finite()), \"NaN in gradient stop\");\n}","typeGuard":"fn is_valid_color(c: &Color) -> bool {\n    [c.r, c.g, c.b, c.a].iter().all(|ch| ch.is_finite())\n}","tryCatchPattern":null,"preventionTips":["Guard every division feeding color math (normalize denominators with max(EPSILON))","Clamp interpolation parameters t to 0..=1 before lerping colors","Validate theme/data-driven colors at load time with is_finite checks","Prefer from_rgba8 for fixed palettes so NaN cannot enter"],"tags":["rust","iced","tiny-skia","gradient","nan","color"],"backgroundTag":"nan-color-component","analyzedSha":"3de451447bd28217bb535632867550908e29d5d0","analyzedAt":"2026-08-17T10:40:26.997Z","contentChangedAt":"2026-08-17T10:40:26.997Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}