gohugoio/hugo · critical

permalinks configuration invalid: unknown value %q for key %

Error message

permalinks configuration invalid: unknown value %q for key %q

What it means

Hugo throws this at the top-level permalinks switch when a value in the `permalinks` map is neither a string (old flat form) nor a params map (new `[permalinks.kind]` form). The decoder at permalinks.go:596-598 hits its `default` arm, meaning the config shape itself is unrecognizable. Build aborts during config load.

Source

Thrown at resources/page/permalinks.go:597

		case hmaps.Params:
			// [permalinks.kind]
			//   section = '...'
			if !hstrings.InSlice(permalinksKindsSupport, k) {
				return nil, fmt.Errorf("permalinks configuration not supported for kind %q, supported kinds are %v", k, permalinksKindsSupport)
			}
			for k2, v2 := range v {
				switch v2 := v2.(type) {
				case string:
					configs = append(configs,
						PermalinkConfig{Target: PageMatcher{Kind: k, Path: sectionToPathGlob(k2)}, Pattern: v2},
					)
				default:
					return nil, fmt.Errorf("permalinks configuration invalid: unknown value %q for key %q for kind %q", v2, k2, k)
				}
			}

		default:
			return nil, fmt.Errorf("permalinks configuration invalid: unknown value %q for key %q", v, k)
		}
	}
	return configs, nil
}

View on GitHub (pinned to 52c9bd7908)

Solutions

  1. Ensure each top-level `permalinks` value is either a quoted string pattern or a sub-table of section-to-string entries.
  2. Run `hugo config` and grep for `permalinks` to inspect the decoded structure.
  3. If using YAML, quote patterns explicitly to avoid implicit type coercion.
  4. Strip any null/empty entries from the permalinks map.

Example fix

# config.yaml -- before
permalinks:
  posts:

# after
permalinks:
  posts: /posts/:slug/
Defensive patterns

Strategy: validation

Validate before calling

// Validate that every top-level permalinks value is string or map[string]any.
func validatePermalinksTop(m map[string]any) error {
	for k, v := range m {
		switch v.(type) {
		case string, map[string]any:
		default:
			return fmt.Errorf("permalinks[%q] must be string or table, got %T", k, v)
		}
	}
	return nil
}

Prevention

When it happens

Trigger: A `permalinks` map entry whose value is a number, bool, array, or nil -- e.g. `permalinks = { posts = 5 }` in YAML, or a TOML `[permalinks]` with `posts = true`. Anything that is not a string and not a sub-table.

Common situations: YAML alias/anchor resolving to a non-string; empty value collapsing to nil; typo turning a pattern into a flag (`posts` instead of `posts = "..."`); migrating config between formats with a lossy converter.

Related errors


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