{"id":"b597432e97864382","repo":"gohugoio/hugo","slug":"xml-root-element-s-has-no-value","errorCode":null,"errorMessage":"XML root element '%s' has no value","messagePattern":"XML root element '(.+?)' has no value","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"parser/metadecoders/decoder.go","lineNumber":300,"sourceCode":"\tcase ORG:\n\t\terr = d.unmarshalORG(data, v)\n\tcase JSON:\n\t\terr = json.Unmarshal(data, v)\n\tcase XML:\n\t\tvar xmlRoot xml.Map\n\t\txmlRoot, err = xml.NewMapXml(data)\n\n\t\tvar xmlValue map[string]any\n\t\tif err == nil {\n\t\t\txmlRootName, err := xmlRoot.Root()\n\t\t\tif err != nil {\n\t\t\t\treturn toFileError(f, data, fmt.Errorf(\"failed to unmarshal XML: %w\", err))\n\t\t\t}\n\n\t\t\t// Get the root value and verify it's a map\n\t\t\trootValue := xmlRoot[xmlRootName]\n\t\t\tif rootValue == nil {\n\t\t\t\treturn toFileError(f, data, fmt.Errorf(\"XML root element '%s' has no value\", xmlRootName))\n\t\t\t}\n\n\t\t\t// Type check before conversion\n\t\t\tmapValue, ok := rootValue.(map[string]any)\n\t\t\tif !ok {\n\t\t\t\treturn toFileError(f, data, fmt.Errorf(\"XML root element '%s' must be a map/object, got %T\", xmlRootName, rootValue))\n\t\t\t}\n\t\t\txmlValue = mapValue\n\t\t}\n\n\t\tswitch v := v.(type) {\n\t\tcase *map[string]any:\n\t\t\t*v = xmlValue\n\t\tcase *any:\n\t\t\t*v = xmlValue\n\t\t}\n\tcase TOML:\n\t\terr = toml.Unmarshal(data, v)","sourceCodeStart":282,"sourceCodeEnd":318,"githubUrl":"https://github.com/gohugoio/hugo/blob/8a468df065a75c1c7cf9f6850f32148746590ea5/parser/metadecoders/decoder.go#L282-L318","documentation":"After successfully identifying the XML root element name, Hugo looks up that root's value in the mxj-produced map; if the value is nil, the root element exists but contains nothing Hugo can turn into data. Since Hugo's XML unmarshaling must yield a map of the root's children, an empty/self-closing root gives it nothing to return, so it fails rather than silently producing an empty result.","triggerScenarios":"Unmarshaling XML whose root element is empty — `<root/>` or `<root></root>` with no child elements, attributes, or text — via a `.xml` data file or `transform.Unmarshal`. The error names the offending root element.","commonSituations":"Remote APIs or RSS/Atom feeds returning an empty result set as a bare self-closing root element; placeholder data files committed before content was added; XML generated by a script that produced no records.","solutions":["Populate the root element with actual child content, or delete the placeholder data file until it has data.","For remote feeds that can legitimately be empty, guard in the template: check the raw content for meaningful children before calling transform.Unmarshal, and handle the empty case explicitly.","If the source is an API, confirm the query/endpoint is correct — an empty root often means the request matched nothing or hit the wrong URL."],"exampleFix":"<!-- before (data/items.xml) -->\n<items/>\n\n<!-- after -->\n<items>\n  <item><name>First</name></item>\n</items>","handlingStrategy":"validation","validationCode":"# Reject empty-root XML before use\nxmllint --xpath 'boolean(/*/node())' data.xml   # prints false for <root/> with no children","typeGuard":null,"tryCatchPattern":"if err != nil && strings.Contains(err.Error(), \"has no value\") {\n    // the XML document's root element is empty — treat as missing data, fail the build input\n}","preventionTips":["Ensure XML data files/feeds contain at least one child element or text under the root, not just `<root/>`","Check remote feeds for empty responses (0 items) before unmarshalling and fail fast with a clear message","Add an ingest-time assertion that parsed data is non-empty before templates consume it"],"tags":["hugo","xml","unmarshal","data-files"],"analyzedSha":"8a468df065a75c1c7cf9f6850f32148746590ea5","analyzedAt":"2026-07-31T21:23:07.045Z","schemaVersion":2}