MaterialDesignInXAML/MaterialDesignInXamlToolkit · error · InvalidOperationException
Invalid HSB values
Error message
Invalid HSB values
What it means
`HsbExtensions.ToColor` converts an HSB color to a WPF `Color` via a six-armed switch on the sector index `i` (0-5). The default arm `throw new InvalidOperationException("Invalid HSB values")` fires when `i` is outside 0-5. After normalizing hue into [0,360) and dividing by 60, `i = (int)Math.Floor(h)` should be 0-5, but a hue of exactly `360.0` slips past the epsilon-tolerant `h.IsCloseTo(360)` guard (0 < double.Epsilon is false) and yields `i = 6`.
Source
Thrown at src/MaterialDesignColors.Wpf/ColorManipulation/HsbExtensions.cs:37
while (h < 0) h += 360;
h /= 60;
int i = (int)Math.Floor(h);
double f = h - i;
double p = b * (1 - s);
double q = b * (1 - s * f);
double t = b * (1 - s * (1 - f));
return i switch
{
0 => Color.FromRgb((byte)b, (byte)t, (byte)p),
1 => Color.FromRgb((byte)q, (byte)b, (byte)p),
2 => Color.FromRgb((byte)p, (byte)b, (byte)t),
3 => Color.FromRgb((byte)p, (byte)q, (byte)b),
4 => Color.FromRgb((byte)t, (byte)p, (byte)b),
5 => Color.FromRgb((byte)b, (byte)p, (byte)q),
_ => throw new InvalidOperationException("Invalid HSB values"),
};
}
public static Hsb ToHsb(this Color color)
{
double r = color.R;
double g = color.G;
double b = color.B;
r /= 255;
g /= 255;
b /= 255;
double[] rgb = [r, g, b];
double max = rgb.Max();
double min = rgb.Min();
double v = max;
double h = max;View on GitHub (pinned to 98edec3a0b)
Solutions
- Normalize hue to [0,360) yourself before calling ToColor: `hue %= 360; if (hue < 0) hue += 360;` and avoid passing exactly 360.
- Upgrade the library / patch `ToColor` so the 360 guard is inclusive (e.g. `if (h >= 360) h = 0;` after the wrap loops) and/or extend the switch to handle `i == 6` as sector 0.
- Validate inputs: reject NaN/infinity and clamp hue to [0,360).
- If consuming the library as-is, wrap the call and on failure retry with `hue = 0`.
Example fix
// before var c = new Hsb(360.0, 1.0, 1.0).ToColor(); // throws Invalid HSB values // after (caller clamp) double hue = 360.0 % 360; if (hue < 0) hue += 360; var c = new Hsb(hue, 1.0, 1.0).ToColor();
Defensive patterns
Strategy: validation
Validate before calling
double SafeHue(double hue)
{
if (double.IsNaN(hue) || double.IsInfinity(hue)) hue = 0;
hue %= 360;
if (hue < 0) hue += 360;
return hue; // strictly [0,360)
}
var c = new Hsb(SafeHue(inputHue), sat, bright).ToColor(); Type guard
static bool IsValidHsb(in Hsb h) =>
!double.IsNaN(h.Hue) && !double.IsInfinity(h.Hue) &&
h.Hue >= 0 && h.Hue < 360 &&
h.Saturation >= 0 && h.Saturation <= 1 &&
h.Brightness >= 0 && h.Brightness <= 1; Try / catch
try { color = hsb.ToColor(); }
catch (InvalidOperationException)
{
// edge: hue landed exactly on 360; retry wrapped
color = new Hsb(0, hsb.Saturation, hsb.Brightness).ToColor();
} Prevention
- Always normalize hue into [0,360) (open upper bound) before calling ToColor.
- Reject NaN/Infinity in HSB inputs.
- Patch/upgrade the library so the 360 guard and switch are inclusive.
When it happens
Trigger: Calling `ToColor` on an `Hsb` whose `Hue` is exactly `360.0` (or any value the normalization leaves at/above 360); constructing an Hsb from code/round-tripping a color whose computed hue lands exactly on the 360 boundary; NaN or infinity in saturation/brightness interacting with the floor.
Common situations: Red colors whose `ToHsb` round-trip produces hue 0/360 boundary values; feeding user-provided HSB triples from a color picker; using a hue slider that allows 360 as its maximum.
Related errors
- Entry {entry.Key} was not of type Color
- Entry {foregroundKey} was not of type Color
- ColorReference does not contain any color
- value
- Value must be positive
AI-assisted analysis of MaterialDesignInXAML/MaterialDesignInXamlToolkit@98edec3a0b (2026-08-13).
Data as JSON: /api/errors/b9210877295a7477.
Report an issue: GitHub.