iOfficeAI/OfficeCLI · error · ArgumentException

Invalid color value: '{original}'. Hue must be a number in d

Error message

Invalid color value: '{original}'. Hue must be a number in degrees.

What it means

Thrown by ParseHueDegrees when the hue token, after stripping an optional 'deg' suffix, is not a parseable number. Hue in hsl()/hsla() is an angle in degrees; it may wrap (modulo 360 is applied) but it must be numeric. Non-numeric tokens like 'red' or empty strings are rejected.

Source

Thrown at src/officecli/Core/ParseHelpers.cs:200

        }
        else
        {
            if (!double.TryParse(token, NumberStyles.Float, CultureInfo.InvariantCulture, out a) || a < 0 || a > 1)
                throw new ArgumentException($"Invalid color value: '{original}'. Alpha must be 0-1 (e.g. 0.5) or 0%-100%.");
        }
        return (byte)Math.Round(a * 255.0);
    }

    private static double ParseHueDegrees(string token, string original)
    {
        token = token.Trim();
        // Strip an optional `deg` suffix (CSS allows it; other angle units
        // — turn/rad/grad — are out of scope for the input vocabulary we care
        // about and would just need their own multipliers if asked for).
        if (token.EndsWith("deg", StringComparison.OrdinalIgnoreCase))
            token = token[..^3].Trim();
        if (!double.TryParse(token, NumberStyles.Float, CultureInfo.InvariantCulture, out var h))
            throw new ArgumentException($"Invalid color value: '{original}'. Hue must be a number in degrees.");
        h %= 360;
        if (h < 0) h += 360;
        return h;
    }

    private static double ParsePercent01(string token, string original)
    {
        token = token.Trim();
        if (!token.EndsWith('%'))
            throw new ArgumentException($"Invalid color value: '{original}'. HSL saturation/lightness must be expressed as a percentage (e.g. 50%).");
        if (!double.TryParse(token[..^1], NumberStyles.Float, CultureInfo.InvariantCulture, out var pct)
            || pct < 0 || pct > 100)
            throw new ArgumentException($"Invalid color value: '{original}'. HSL saturation/lightness must be 0%-100%.");
        return pct / 100.0;
    }

    private static (byte R, byte G, byte B) HslToRgb(double h, double s, double l)
    {

View on GitHub (pinned to 1ced45e900)

Solutions

  1. Supply hue as a number of degrees, e.g. hsl(120,50%,50%) or hsl(120deg,50%,50%).
  2. If you only have a named color, convert it to HSL first (do not put the name in the hue slot).
  3. Validate the hue token is numeric before building the hsl() string.

Example fix

// before
var c = "hsl(red,50%,50%)";
ParseColor(c); // throws 288

// after
var c = "hsl(0,50%,50%)"; // 0 deg = red
ParseColor(c);
Defensive patterns

Strategy: validation

Validate before calling

if (!double.TryParse(hueToken.TrimEnd("deg".ToCharArray()), NumberStyles.Float, CultureInfo.InvariantCulture, out _))
    hueToken = "0";

Type guard

static bool IsValidHue(string token)
{
    var t = token.Trim();
    if (t.EndsWith("deg", StringComparison.OrdinalIgnoreCase)) t = t[..^3].Trim();
    return double.TryParse(t, CultureInfo.InvariantCulture, out _);
}

Try / catch

try { color = ParseColor(spec); }
catch (ArgumentException ex) when (ex.Message.Contains("Hue"))
{ spec = "hsl(0,50%,50%)"; }

Prevention

When it happens

Trigger: Passing hsl(red,50%,50%); passing hsl(,50%,50%) (empty hue); a hue value that was meant to be a named color leaking into the hue slot.

Common situations: Mixing up CSS named-color input with HSL; a templating bug that left the hue token blank; copy-pasting an HSL triple that used a different delimiter and lost the hue.

Related errors


AI-assisted analysis of iOfficeAI/OfficeCLI@1ced45e900 (2026-08-13). Data as JSON: /api/errors/08c2eff8c1f1bc7c. Report an issue: GitHub.