{"record":{"id":"08c2eff8c1f1bc7c","repo":"iOfficeAI/OfficeCLI","slug":"invalid-color-value-original-hue-must-be-a-n","errorCode":null,"errorMessage":"Invalid color value: '{original}'. Hue must be a number in degrees.","messagePattern":"Invalid color value: '(.+?)'\\. Hue must be a number in degrees\\.","errorType":"exception","errorClass":"ArgumentException","httpStatus":null,"severity":"error","filePath":"src/officecli/Core/ParseHelpers.cs","lineNumber":200,"sourceCode":"        }\n        else\n        {\n            if (!double.TryParse(token, NumberStyles.Float, CultureInfo.InvariantCulture, out a) || a < 0 || a > 1)\n                throw new ArgumentException($\"Invalid color value: '{original}'. Alpha must be 0-1 (e.g. 0.5) or 0%-100%.\");\n        }\n        return (byte)Math.Round(a * 255.0);\n    }\n\n    private static double ParseHueDegrees(string token, string original)\n    {\n        token = token.Trim();\n        // Strip an optional `deg` suffix (CSS allows it; other angle units\n        // — turn/rad/grad — are out of scope for the input vocabulary we care\n        // about and would just need their own multipliers if asked for).\n        if (token.EndsWith(\"deg\", StringComparison.OrdinalIgnoreCase))\n            token = token[..^3].Trim();\n        if (!double.TryParse(token, NumberStyles.Float, CultureInfo.InvariantCulture, out var h))\n            throw new ArgumentException($\"Invalid color value: '{original}'. Hue must be a number in degrees.\");\n        h %= 360;\n        if (h < 0) h += 360;\n        return h;\n    }\n\n    private static double ParsePercent01(string token, string original)\n    {\n        token = token.Trim();\n        if (!token.EndsWith('%'))\n            throw new ArgumentException($\"Invalid color value: '{original}'. HSL saturation/lightness must be expressed as a percentage (e.g. 50%).\");\n        if (!double.TryParse(token[..^1], NumberStyles.Float, CultureInfo.InvariantCulture, out var pct)\n            || pct < 0 || pct > 100)\n            throw new ArgumentException($\"Invalid color value: '{original}'. HSL saturation/lightness must be 0%-100%.\");\n        return pct / 100.0;\n    }\n\n    private static (byte R, byte G, byte B) HslToRgb(double h, double s, double l)\n    {","sourceCodeStart":182,"sourceCodeEnd":218,"githubUrl":"https://github.com/iOfficeAI/OfficeCLI/blob/1ced45e900782c5083ed550ddf328ee974e425e7/src/officecli/Core/ParseHelpers.cs#L182-L218","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Supply hue as a number of degrees, e.g. hsl(120,50%,50%) or hsl(120deg,50%,50%).","If you only have a named color, convert it to HSL first (do not put the name in the hue slot).","Validate the hue token is numeric before building the hsl() string."],"exampleFix":"// before\nvar c = \"hsl(red,50%,50%)\";\nParseColor(c); // throws 288\n\n// after\nvar c = \"hsl(0,50%,50%)\"; // 0 deg = red\nParseColor(c);","handlingStrategy":"validation","validationCode":"if (!double.TryParse(hueToken.TrimEnd(\"deg\".ToCharArray()), NumberStyles.Float, CultureInfo.InvariantCulture, out _))\n    hueToken = \"0\";","typeGuard":"static bool IsValidHue(string token)\n{\n    var t = token.Trim();\n    if (t.EndsWith(\"deg\", StringComparison.OrdinalIgnoreCase)) t = t[..^3].Trim();\n    return double.TryParse(t, CultureInfo.InvariantCulture, out _);\n}","tryCatchPattern":"try { color = ParseColor(spec); }\ncatch (ArgumentException ex) when (ex.Message.Contains(\"Hue\"))\n{ spec = \"hsl(0,50%,50%)\"; }","preventionTips":["Always supply hue as a numeric degree.","Convert named colors to HSL before building an hsl() string.","Validate the hue token is non-empty."],"tags":["color","validation","argument","hsl","hue"],"backgroundTag":null,"analyzedSha":"1ced45e900782c5083ed550ddf328ee974e425e7","analyzedAt":"2026-08-13T13:01:07.193Z","schemaVersion":2},"datasetVersion":"2026-08-13T14:17:21.547Z"}