gohugoio/hugo · error

unmarshal failed

Error message

unmarshal failed: %w

What it means

Thrown by Decoder.UnmarshalTo (parser/metadecoders/decoder.go:332) as the catch-all wrapper when the underlying format-specific decoder (json.Unmarshal, toml.Unmarshal, ORG parser, or the XML path's residual error) returns a non-nil error that isn't already handled by an earlier specific branch. The %w preserves the original error and toFileError attaches file/content context.

Solutions

  1. Read the wrapped error for the exact syntax issue and line/column if provided.
  2. Validate the file with the appropriate linter (e.g. jq for JSON, a TOML validator) and fix the syntax.
  3. Use Hugo's file-position hints in the error output to jump to the offending location.
  4. If the error is in front matter, ensure correct delimiters (+++ vs ---) and format.

Example fix

// before: data/bad.json
{ "k": 1, }   // trailing comma

// after
{ "k": 1 }
Defensive patterns

Strategy: try-catch

Validate before calling

// Lint JSON/TOML before loading.
func isValidJSON(data []byte) bool {
    return json.Valid(data)
}

Try / catch

if err := dec.UnmarshalTo(data, f, &m); err != nil {
    return fmt.Errorf("malformed %s data: %w", f, err)
}

Prevention

When it happens

Trigger: Malformed JSON (syntax error, trailing comma), malformed TOML, invalid ORG-mode syntax, or any decode-time error from the format library that isn't intercepted by the dedicated XML/CSV branches. Essentially any well-formedness violation in a data/front-matter file.

Common situations: A syntax error in a front-matter block (bad YAML indent caught by the YAML branch is separate, but JSON/TOML/ORG errors land here); a corrupt JSON data file under data/; a TOML config with a duplicate key or bad quoting; an ORG file with unsupported syntax.

Related errors


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

Appendix: source

Thrown at parser/metadecoders/decoder.go:332

		case *any:
			*v = xmlValue
		}
	case TOML:
		err = toml.Unmarshal(data, v)
	case YAML:
		return UnmarshalYaml(data, v)
	case CSV:
		return d.unmarshalCSV(data, v)

	default:
		return fmt.Errorf("unmarshal of format %q is not supported", f)
	}

	if err == nil {
		return nil
	}

	return toFileError(f, data, fmt.Errorf("unmarshal failed: %w", err))
}

func (d Decoder) unmarshalCSV(data []byte, v any) error {
	r := csv.NewReader(bytes.NewReader(data))
	r.Comma = d.Delimiter
	r.Comment = d.Comment
	r.LazyQuotes = d.LazyQuotes

	records, err := r.ReadAll()
	if err != nil {
		return err
	}

	switch vv := v.(type) {
	case *any:
		switch d.TargetType {
		case "map":
			if len(records) < 2 {

View on GitHub (pinned to 52c9bd7908)