{"record":{"id":"a7477df88dded255","repo":"mxgmn/MarkovJunior","slug":"xelement-xelem-name-didn-t-have-attribute-attribute","errorCode":null,"errorMessage":"xelement {xelem.Name} didn't have attribute {attribute}","messagePattern":"xelement (.+?) didn't have attribute (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"source/XMLHelper.cs","lineNumber":14,"sourceCode":"﻿// Copyright (C) 2022 Maxim Gumin, The MIT License (MIT)\n\nusing System;\nusing System.Linq;\nusing System.Xml.Linq;\nusing System.ComponentModel;\nusing System.Collections.Generic;\n\nstatic class XMLHelper\n{\n    public static T Get<T>(this XElement xelem, string attribute)\n    {\n        XAttribute a = xelem.Attribute(attribute);\n        if (a == null) throw new Exception($\"xelement {xelem.Name} didn't have attribute {attribute}\");\n        return (T)TypeDescriptor.GetConverter(typeof(T)).ConvertFromInvariantString(a.Value);\n    }\n\n    public static T Get<T>(this XElement xelem, string attribute, T dflt)\n    {\n        XAttribute a = xelem.Attribute(attribute);\n        return a == null ? dflt : (T)TypeDescriptor.GetConverter(typeof(T)).ConvertFromInvariantString(a.Value);\n    }\n\n    public static int LineNumber(this XElement xelem) => ((System.Xml.IXmlLineInfo)xelem).LineNumber;\n\n    public static IEnumerable<XElement> Elements(this XElement xelement, params string[] names) => xelement.Elements().Where(e => names.Any(n => n == e.Name));\n    public static IEnumerable<XElement> MyDescendants(this XElement xelem, params string[] tags)\n    {\n        Queue<XElement> q = new();\n        q.Enqueue(xelem);\n\n        while (q.Any())","sourceCodeStart":1,"sourceCodeEnd":32,"githubUrl":"https://github.com/mxgmn/MarkovJunior/blob/42aaf24bcf54ae164fba49c0a59348297904a676/source/XMLHelper.cs#L1-L32","documentation":"XMLHelper.Get<T> is an extension method that reads an XML attribute off an XElement and converts it to type T. It throws this generic Exception when the requested attribute does not exist on the element. The library throws eagerly (no default overload is used) because the caller explicitly asked for a required attribute, so silently returning null/default would hide malformed XML data.","triggerScenarios":"Calling xelem.Get<string>(\"foo\") (or Get<T> with any T) when the XElement has no attribute named 'foo'. This happens whenever the XML does not conform to the expected schema — a missing attribute in the source file, a typo in the attribute name passed to Get, case mismatch (XML attribute names are case-sensitive), or an element loaded from a different/older schema version that lacks the attribute.","commonSituations":"Hand-edited or third-party XML config/data files missing required attributes; schema version drift where older files lack attributes the new code expects; misspelled or wrong-cased attribute names in code; parsing XML from external sources (web APIs, user uploads) without validating it first; refactorings where the XML format was changed but the reader code was not.","solutions":["Check the attribute actually exists on the element at that point: log/inspect xelem and its Attributes() list, and verify the name and casing match exactly.","Fix the attribute name passed to Get — XML names are case-sensitive, so 'Id' and 'id' are different attributes.","Fix the XML source file so it contains the required attribute for that element.","If the attribute is legitimately optional, switch to the overload with a default value: xelem.Get(\"foo\", defaultValue).","Validate the XML against its XSD/schema (or pre-scan elements with a helper) before parsing so missing attributes are reported with a clear message.","Wrap the Get call in try-catch and produce an error message that includes the element name, line info (IXmlLineInfo), and attribute name for easier debugging."],"exampleFix":"// before\nstring id = elem.Get<string>(\"ID\"); // throws if attribute missing\n// after\nstring id = elem.Get(\"ID\", \"\"); // optional with default\n// or validate first:\nif (elem.Attribute(\"ID\") == null)\n    throw new InvalidDataException($\"Element {elem.Name} at {((IXmlLineInfo)elem).LineNumber} is missing required attribute 'ID'.\");\nstring id = elem.Get<string>(\"ID\");","handlingStrategy":"validation","validationCode":"static bool HasAttr(System.Xml.Linq.XElement e, string name) => e != null && e.Attribute(name) != null;\n// before parsing:\nif (!HasAttr(elem, \"ID\")) throw new InvalidDataException($\"{elem.Name} missing attribute 'ID'\");\nstring id = elem.Get<string>(\"ID\");","typeGuard":"static bool TryGetAttr<T>(System.Xml.Linq.XElement e, string name, out T value)\n{\n    var a = e?.Attribute(name);\n    if (a == null) { value = default; return false; }\n    value = (T)System.ComponentModel.TypeDescriptor.GetConverter(typeof(T)).ConvertFromInvariantString(a.Value);\n    return true;\n}","tryCatchPattern":"try\n{\n    var value = elem.Get<string>(\"ID\");\n}\ncatch (Exception ex) when (ex.Message.StartsWith(\"xelement\"))\n{\n    throw new InvalidDataException($\"Missing required attribute on element '{elem.Name}' at line {((System.Xml.IXmlLineInfo)elem).LineNumber}\", ex);\n}","preventionTips":["Validate XML files against an XSD/schema before parsing.","Use the Get overload with a default value for genuinely optional attributes.","Match attribute names exactly — XML is case-sensitive; keep names as constants.","When reporting failures, include element name and line number to speed diagnosis.","For external/user-supplied XML, pre-scan required attributes per element type and fail early with a summary of all missing ones."],"tags":["xml","missing-attribute","config","csharp"],"backgroundTag":"missing-required-argument","analyzedSha":"42aaf24bcf54ae164fba49c0a59348297904a676","analyzedAt":"2026-09-13T15:41:34.700Z","contentChangedAt":"2026-09-13T15:41:34.700Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}