{"record":{"id":"8268e73681e8ae8e","repo":"MaterialDesignInXAML/MaterialDesignInXamlToolkit","slug":"the-attribute-class-was-not-found","errorCode":null,"errorMessage":"The attribute 'class' was not found","messagePattern":"The attribute 'class' was not found","errorType":"exception","errorClass":"InvalidDataException","httpStatus":null,"severity":"error","filePath":"src/MaterialDesignToolkit.ResourceGeneration/Program.cs","lineNumber":238,"sourceCode":"        var javaScript = string.Format(\"var swatches={0};\", json);\n\n        File.WriteAllText(file, javaScript);\n    }\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            );","sourceCodeStart":220,"sourceCodeEnd":256,"githubUrl":"https://github.com/MaterialDesignInXAML/MaterialDesignInXamlToolkit/blob/98edec3a0b96ef272c587b14bcd67ef5f928a7ed/src/MaterialDesignToolkit.ResourceGeneration/Program.cs#L220-L256","documentation":"CreateJsonColourPair reads each <li> swatch element from the snippet XML and expects it to carry a class= attribute, used to look up the foreground text color (light vs dark) for that swatch. liElement.Attribute(\"class\")?.Value returns null when the attribute is absent, and the ?? coalesce throws InvalidDataException. It fires because the snippet's <li> markup does not match the assumed shape — every swatch li must have class=\"color ...\" for the foreground-mapping table to work.","triggerScenarios":"A particular <li> in MaterialColourSwatchesSnippet.xml has no class attribute — e.g. a header <li>, a newly added accent row, or markup produced by a changed scraping template. The JSON generation path (args containing 'json' or the first positional arg path) iterates sectionElement.Element(\"ul\").Elements(\"li\").Skip(1) and calls CreateJsonColourPair on each, so the first unclassed li trips it.","commonSituations":"The upstream Material Design colour page changed its HTML structure; the snippet was hand-edited and a class attribute was removed; a new colour was appended without the class attribute; the scrape step was run against a different page variant that omits per-li classes.","solutions":["Inspect MaterialColourSwatchesSnippet.xml and find the <li> elements inside each <section>/<ul>; confirm every swatch li has a class attribute.","Re-scrape the snippet from the canonical Material Design colour swatches page so the class attributes are restored.","If the missing-class li is a non-swatch row (header, divider), change CreateJsonColourPair to skip li elements that lack both a class and the expected two <span> children rather than throwing.","Make the error message include the offending li's name/hex and outer XML so the bad element is identifiable."],"exampleFix":"// before\nvar liClass = liElement.Attribute(\"class\")?.Value ??\n              throw new InvalidDataException(\"The attribute 'class' was not found\");\n\n// after\nvar classAttr = liElement.Attribute(\"class\");\nif (classAttr is null)\n    throw new InvalidDataException(\n        $\"The attribute 'class' was not found on <li> for swatch '{name}' (hex '{hex}'): {liElement}\");\nvar liClass = classAttr.Value;","handlingStrategy":"validation","validationCode":"var classAttr = liElement.Attribute(\"class\");\nif (classAttr is null)\n    throw new InvalidDataException(\n        $\"<li> for swatch '{name}' is missing the 'class' attribute: {liElement}\");\nvar liClass = classAttr.Value;","typeGuard":"static bool LiHasClass(XElement li) => li.Attribute(\"class\") is not null;\n\n// usage before creating the JSON pair\nvar swatchLis = section.Element(\"ul\")!.Elements(\"li\").Skip(1).Where(LiHasClass);","tryCatchPattern":"try\n{\n    var pair = CreateJsonColourPair(liElement);\n}\ncatch (InvalidDataException ex) when (ex.Message.Contains(\"'class' was not found\"))\n{\n    // skip non-swatch rows (headers/dividers) instead of aborting the whole JSON build\n    Console.Error.WriteLine($\"Skipping li without class: {liElement}\");\n    continue;\n}","preventionTips":["Treat the snippet schema as a contract: before generation, validate that every swatch <li> has a class attribute.","When scraping the snippet, drop or skip header <li> rows so only real swatches reach the generator.","Make the error include the li's name/hex and outer XML so the offending element is immediately identifiable.","Run a schema check (e.g. all ul > li except first have a class attribute) as a build pre-step."],"tags":["csharp","xml","codegen","parsing"],"backgroundTag":null,"analyzedSha":"98edec3a0b96ef272c587b14bcd67ef5f928a7ed","analyzedAt":"2026-08-13T14:31:19.111Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}