gohugoio/hugo · error

failed to decode media types

Error message

failed to decode media types: %w

What it means

Returned by DecodeContentTypes when config.DecodeNamespace fails while building ContentTypes. Wraps the inner error with %w (unwrappable). The inner failure is usually the 'unknown media type %q' error (447) or a mapstructure decode error on a ContentTypeConfig value, but any failure in the buildConfig closure bubbles up here.

Solutions

  1. Read the wrapped (%w) error message to identify the specific cause (unknown type vs decode error).
  2. Ensure every referenced content type key exists in the decoded media Types.
  3. Make sure each content type entry is a table/map, not a scalar.
  4. Validate the full [mediaTypes] + content types config together with `hugo config`.

Example fix

# before
[mediaTypes]
[mediaTypes."text/markdown"]
suffixes = ["md"]
# content type references text/md (typo)

# after
[mediaTypes]
[mediaTypes."text/markdown"]
suffixes = ["md"]
# reference matches exactly: text/markdown
Defensive patterns

Strategy: try-catch

Validate before calling

// Pre-check that all content type values are maps and keys are known MIMEs.
func preflightContentTypes(in map[string]any) error {
    for k, v := range in {
        if _, ok := v.(map[string]any); !ok {
            return fmt.Errorf("content type %q must be a map", k)
        }
    }
    return nil
}

Try / catch

ns, err := media.DecodeContentTypes(in, types)
if err != nil {
    // err wraps the concrete cause; unwrap for messaging
    return fmt.Errorf("decode content types: %w", err)
}

Prevention

When it happens

Trigger: Calling DecodeContentTypes with a content types config map whose build step fails: unknown media type reference, malformed mapstructure values, or a non-map input passed as the config source. Fires during Hugo config load.

Common situations: Same as 447 plus structurally invalid config: a content type entry whose value is not a map (e.g. a bare string), or a media type referenced before it is defined because the media types decode ran against a stale/empty Types set.

Understand the failure class

Related errors


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

Appendix: source

Thrown at media/config.go:216

			}
		}

		for k := range s {
			mediaType, found := types.GetByType(k)
			if !found {
				return c, nil, fmt.Errorf("unknown media type %q", k)
			}
			c.types = append(c.types, mediaType)
		}

		c.init(types)

		return c, s, nil
	}

	ns, err := config.DecodeNamespace[map[string]ContentTypeConfig](in, buildConfig)
	if err != nil {
		return nil, fmt.Errorf("failed to decode media types: %w", err)
	}
	return ns, nil
}

// DecodeTypes decodes the given map of media types.
func DecodeTypes(in map[string]any) (*config.ConfigNamespace[map[string]MediaTypeConfig, Types], error) {
	buildConfig := func(v any) (Types, any, error) {
		m, err := hmaps.ToStringMapE(v)
		if err != nil {
			return nil, nil, err
		}
		if m == nil {
			m = map[string]any{}
		}
		m = hmaps.CleanConfigStringMap(m)
		// Merge with defaults.
		hmaps.MergeShallow(m, defaultMediaTypesConfig)

View on GitHub (pinned to 52c9bd7908)