{"record":{"id":"2dfe67201550b327","repo":"MaterialDesignInXAML/MaterialDesignInXamlToolkit","slug":"unable-to-map-foreground-color-from-class-liclass","errorCode":null,"errorMessage":"Unable to map foreground color from class {liClass}","messagePattern":"Unable to map foreground color from class (.+?)","errorType":"exception","errorClass":"Exception","httpStatus":null,"severity":"error","filePath":"src/MaterialDesignToolkit.ResourceGeneration/Program.cs","lineNumber":241,"sourceCode":"    }\n\n    private static JObject CreateJsonColourPair(XElement liElement)\n    {\n        var name = liElement.Elements(\"span\").First().Value;\n        var hex = liElement.Elements(\"span\").Last().Value;\n\n        var prefix = \"Primary\";\n        if (name.StartsWith(\"A\"))\n        {\n            prefix = \"Secondary\";\n            name = name.Skip(1).Aggregate(\"\", (current, next) => current + next);\n        }\n\n        var liClass = liElement.Attribute(\"class\")?.Value ??\n                      throw new InvalidDataException(\"The attribute 'class' was not found\");\n        Color foregroundColour;\n        if (!ClassNameToForegroundIndex.TryGetValue(liClass, out foregroundColour))\n            throw new Exception(\"Unable to map foreground color from class \" + liClass);\n\n        var foreGroundColorHex = string.Format(\"#{0}{1}{2}\",\n            ByteToHex(foregroundColour.R),\n            ByteToHex(foregroundColour.G),\n            ByteToHex(foregroundColour.B));\n\n        var foregroundOpacity = Math.Round(foregroundColour.A / (255.0), 2);\n\n        return new JObject(\n            new JProperty(\"backgroundName\", string.Format(\"{0}{1}\", prefix, name)),\n            new JProperty(\"backgroundColour\", hex),\n            new JProperty(\"foregroundName\", string.Format(\"{0}{1}Foreground\", prefix, name)),\n            new JProperty(\"foregroundColour\", foreGroundColorHex),\n            new JProperty(\"foregroundOpacity\", foregroundOpacity)\n            );\n    }\n\n    private static Tuple<string, XDocument> ToResourceDictionary(XElement sectionElement, out bool empty, bool named = false, ColorMode mode = ColorMode.All)","sourceCodeStart":223,"sourceCodeEnd":259,"githubUrl":"https://github.com/MaterialDesignInXAML/MaterialDesignInXamlToolkit/blob/98edec3a0b96ef272c587b14bcd67ef5f928a7ed/src/MaterialDesignToolkit.ResourceGeneration/Program.cs#L223-L259","documentation":"In CreateJsonColourPair, after extracting the li's class attribute, the code looks it up in the fixed dictionary ClassNameToForegroundIndex, whose only keys are 'color', 'color ', 'color dark divide', 'color dark', 'color dark-strong', 'color light-strong', and 'color dark-when-small'. Dictionary.TryGetValue returns false for any class string that is not an EXACT, case-sensitive match, and the code then throws a generic System.Exception (note: not InvalidDataException) with the offending class appended. So this fires when the class attribute value is a new or differently-spaced variant the map does not recognise.","triggerScenarios":"An <li> carries a class attribute whose value is not one of the seven hard-coded keys — e.g. 'color dark-when-large', 'color light', 'color  dark' (double space), 'Color dark' (capital C), or any trailing-space variant other than the one 'color ' entry. The message includes the actual liClass so you can see exactly which string failed.","commonSituations":"The Material Design swatches page introduced a new foreground class (e.g. a responsive variant); the scrape normalised/did not normalise whitespace differently than the map expects; copy-paste introduced a trailing space or different case; an older snippet is paired with newer map keys or vice-versa.","solutions":["Read the liClass value from the error message and add it (with the correct foreground Color) to ClassNameToForegroundIndex.","Before adding a new key, normalise whitespace on both sides: collapse runs of spaces and trim the class string when building the dictionary and when reading liClass, so 'color  dark' and 'color dark ' both match.","If the new class is semantically identical to an existing one, alias it to the same Color value rather than inventing a new colour.","Throw InvalidDataException instead of Exception and include the set of known keys in the message to make future misses self-diagnosing."],"exampleFix":"// before\nvar liClass = liElement.Attribute(\"class\")?.Value;\nColor foregroundColour;\nif (!ClassNameToForegroundIndex.TryGetValue(liClass, out foregroundColour))\n    throw new Exception(\"Unable to map foreground color from class \" + liClass);\n\n// after\nvar rawClass = liElement.Attribute(\"class\")?.Value ?? \"\";\n// collapse whitespace so 'color  dark' / 'color dark ' still match a canonical key\nvar liClass = string.Join(\" \", rawClass.Split(' ', StringSplitOptions.RemoveEmptyEntries));\nColor foregroundColour;\nif (!ClassNameToForegroundIndex.TryGetValue(liClass, out foregroundColour))\n    throw new InvalidDataException(\n        $\"Unable to map foreground color from class '{liClass}' (raw='{rawClass}'). \" +\n        $\"Known classes: {string.Join(\", \", ClassNameToForegroundIndex.Keys)}\");","handlingStrategy":"validation","validationCode":"var rawClass = liElement.Attribute(\"class\")?.Value ?? \"\";\nvar liClass = string.Join(\" \", rawClass.Split(' ', StringSplitOptions.RemoveEmptyEntries));\nif (!ClassNameToForegroundIndex.ContainsKey(liClass))\n    throw new InvalidDataException(\n        $\"Unknown swatch class '{liClass}'. Expected one of: {string.Join(\", \", ClassNameToForegroundIndex.Keys)}\");","typeGuard":"static readonly HashSet<string> KnownForegroundClasses =\n    ClassNameToForegroundIndex.Keys.ToHashSet();\n\nstatic bool IsKnownForegroundClass(string? raw)\n{\n    if (raw is null) return false;\n    var norm = string.Join(\" \", raw.Split(' ', StringSplitOptions.RemoveEmptyEntries));\n    return KnownForegroundClasses.Contains(norm);\n}","tryCatchPattern":"try\n{\n    /* lookup */\n}\ncatch (Exception ex) when (ex.Message.StartsWith(\"Unable to map foreground color from class\"))\n{\n    // surface the offending class + the full known-key set, then abort or skip\n    Console.Error.WriteLine(ex.Message + \" -- known keys: \" + string.Join(\", \", ClassNameToForegroundIndex.Keys));\n    throw;\n}","preventionTips":["Normalise whitespace (trim + collapse internal spaces) on both the dictionary keys and the incoming liClass so spacing variants cannot cause a miss.","Keep ClassNameToForegroundIndex as the single source of truth for foreground classes and update it whenever the upstream Material Design page adds a class.","Throw InvalidDataException with the list of known keys so misses are self-diagnosing.","Add a unit test that feeds each known snippet class through the lookup to catch drift early."],"tags":["csharp","xml","codegen","color","material-design"],"backgroundTag":null,"analyzedSha":"98edec3a0b96ef272c587b14bcd67ef5f928a7ed","analyzedAt":"2026-08-13T14:31:19.111Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}