gohugoio/hugo · error
failed to decode related config: %w
Error message
failed to decode related config: %w
What it means
Emitted when the [related] config section is set but related.DecodeConfig cannot decode it into Hugo's related-content configuration (index definitions, thresholds, etc.). Hugo only decodes this section when explicitly present (otherwise it falls back to related.DefaultConfig), so this error always points at a user-authored [related] block.
Source
Thrown at config/allconfig/alldecoders.go:360
for k, v := range m {
if k == "" || v == "" {
delete(m, k)
}
}
p.c.Taxonomies = m
}
return nil
},
},
"related": {
key: "related",
weight: 100, // This needs to be decoded after taxonomies.
decode: func(d decodeWeight, p decodeConfig) error {
if p.p.IsSet(d.key) {
var err error
p.c.Related, err = related.DecodeConfig(p.p.GetParams(d.key))
if err != nil {
return fmt.Errorf("failed to decode related config: %w", err)
}
} else {
p.c.Related = related.DefaultConfig
if _, found := p.c.Taxonomies["tag"]; found {
p.c.Related.Add(related.IndexConfig{Name: "tags", Weight: 80, Type: related.TypeBasic})
}
}
return nil
},
},
"cascade": {
key: "cascade",
decode: func(d decodeWeight, p decodeConfig) error {
var err error
p.c.Cascade, err = page.DecodeCascadeConfig(p.p.Get(d.key))
return err
},View on GitHub ↗ (pinned to 8a468df065)
Solutions
- Structure indices as an array of tables: [[related.indices]] entries each with name/weight, not fields directly under [related].
- Make threshold, weight and toLower the correct types (numbers/booleans, not strings).
- Compare your block against the current docs at gohugo.io/content-management/related/ for your Hugo version.
- Delete the [related] section entirely to fall back to Hugo's sensible defaults if you don't need customization.
Example fix
# before [related] name = 'keywords' weight = '100' # after [related] threshold = 80 [[related.indices]] name = 'keywords' weight = 100
Defensive patterns
Strategy: validation
Validate before calling
// related config must decode into related.Config: check shape first
rel, ok := cfg.Get("related").(map[string]any)
if ok {
if idx, ok := rel["indices"]; ok {
if _, ok := idx.([]any); !ok {
return errors.New("related.indices must be an array of tables")
}
}
} Try / catch
conf, err := allconfig.LoadConfig(opts)
if err != nil && strings.Contains(err.Error(), "related config") {
// point the user at the [related] section specifically
return err
} Prevention
- Model your [related] block on the documented default (threshold, includeNewer, toLower, [[related.indices]])
- indices must be an array of tables ([[related.indices]] in TOML), each with name and weight
- When overriding related config you replace the default entirely — supply the full structure, not a partial patch
- Keep weight/threshold numeric; strings there break mapstructure decoding
When it happens
Trigger: A [related] section whose shape related.DecodeConfig rejects: 'indices' not being a list of maps, an index entry missing 'name', invalid 'type' values, non-numeric threshold/weight values, or wrong nesting such as putting index fields directly under [related] instead of [[related.indices]].
Common situations: Copying a related-content snippet between YAML and TOML and losing the array-of-tables structure ([[related.indices]] in TOML vs a YAML list); setting threshold or weight as strings; using fields from newer Hugo versions (e.g. type = 'fragments' options, cardinalityThreshold) on an older Hugo.
Related errors
- no related config provided
- empty related config provided
- invalid index type %q. Must be one of %v
- cardinalityThreshold threshold must be between 0 and 100
- language %q not found
AI-assisted analysis of gohugoio/hugo@8a468df065 (2026-07-31).
Data as JSON: /data/errors/da111fb8c783e624.json.
Report an issue: GitHub ↗.