gohugoio/hugo · error

XML root element ' ' has no value

Error message

XML root element '%s' has no value

What it means

Thrown in the XML branch of Decoder.UnmarshalTo (parser/metadecoders/decoder.go:300) when the XML root element parses successfully and has a name, but its value is nil (the root element is empty or self-closing with no children/text). Hugo requires the root to carry a value, so an empty <root/> triggers this error naming the element.

Solutions

  1. Populate the root element with at least one child element or text value.
  2. If empty data is legitimate, handle the empty-data case upstream before feeding it to Hugo.
  3. Switch to JSON if the XML is always a flat key/value container.

Example fix

<!-- before -->
<root/>

<!-- after -->
<root>
  <item>value</item>
</root>
Defensive patterns

Strategy: validation

Validate before calling

// Ensure XML root has content before decoding.
func xmlRootHasContent(data []byte) bool {
    return bytes.Count(data, []byte("<")) > 1
}

Try / catch

if err := dec.UnmarshalTo(data, metadecoders.XML, &m); err != nil {
    return fmt.Errorf("empty XML root: %w", err)
}

Prevention

When it happens

Trigger: An XML data file whose root element is empty: <root></root> or <root/>; an element that contains only attributes but no child elements or text, which mxj represents as nil.

Common situations: Exporting an empty dataset to XML; a feed endpoint returning an empty container; a templating tool emitting a self-closing root.

Related errors


AI-assisted analysis of gohugoio/hugo@52c9bd7908 (2026-08-09). Data as JSON: /api/errors/b597432e97864382. Report an issue: GitHub.

Appendix: source

Thrown at parser/metadecoders/decoder.go:300

	case ORG:
		err = d.unmarshalORG(data, v)
	case JSON:
		err = json.Unmarshal(data, v)
	case XML:
		var xmlRoot xml.Map
		xmlRoot, err = xml.NewMapXml(data)

		var xmlValue map[string]any
		if err == nil {
			xmlRootName, err := xmlRoot.Root()
			if err != nil {
				return toFileError(f, data, fmt.Errorf("failed to unmarshal XML: %w", err))
			}

			// Get the root value and verify it's a map
			rootValue := xmlRoot[xmlRootName]
			if rootValue == nil {
				return toFileError(f, data, fmt.Errorf("XML root element '%s' has no value", xmlRootName))
			}

			// Type check before conversion
			mapValue, ok := rootValue.(map[string]any)
			if !ok {
				return toFileError(f, data, fmt.Errorf("XML root element '%s' must be a map/object, got %T", xmlRootName, rootValue))
			}
			xmlValue = mapValue
		}

		switch v := v.(type) {
		case *map[string]any:
			*v = xmlValue
		case *any:
			*v = xmlValue
		}
	case TOML:
		err = toml.Unmarshal(data, v)

View on GitHub (pinned to 52c9bd7908)