gohugoio/hugo · error
failed to create config: %w
Error message
failed to create config: %w
What it means
Returned on the no-modules-config path: when no module contributed config files, Hugo still checks configs.transientErr() and wraps any deferred validation error as 'failed to create config'. Transient errors are problems detected during typed-config construction that are deliberately deferred (so partial-config commands can still run) and only fatal here, at the end of a full LoadConfig.
Source
Thrown at config/allconfig/load.go:93
moduleConfig, modulesClient, err := l.loadModules(configs, d.IgnoreModuleDoesNotExist)
if err != nil {
return nil, fmt.Errorf("failed to load modules: %w", err)
}
if len(l.ModulesConfigFiles) > 0 {
// Config merged in from modules.
// Re-read the config.
configs, err = fromLoadConfigResult(d.Fs, d.Logger, res)
if err != nil {
return nil, fmt.Errorf("failed to create config from modules config: %w", err)
}
if err := configs.transientErr(); err != nil {
return nil, fmt.Errorf("failed to create config from modules config: %w", err)
}
configs.LoadingInfo.ConfigFiles = append(configs.LoadingInfo.ConfigFiles, l.ModulesConfigFiles...)
} else if err := configs.transientErr(); err != nil {
return nil, fmt.Errorf("failed to create config: %w", err)
}
configs.Modules = moduleConfig.AllModules
configs.ModulesClient = modulesClient
if !d.SkipNpmCheck && npm.NpmPackNeedsUpdate(d.Fs, configs.Modules) {
d.Logger.Warnln(`npm dependencies are out of sync, please run "hugo mod npm pack" (you may also want to run "npm install" after that)`)
}
if err := configs.Init(d.Fs, d.Logger); err != nil {
return nil, fmt.Errorf("failed to init config: %w", err)
}
loggers.SetGlobalLogger(d.Logger)
return
}
View on GitHub ↗ (pinned to 8a468df065)
Solutions
- Read the wrapped transient error text — it describes the actual invalid setting; fix that key in your config.
- Check per-language override blocks ([languages.xx.*]) for values inconsistent with root config.
- After a Hugo upgrade, run `hugo config` and review the release notes for options that became errors.
- Reduce config to a minimal set and reintroduce sections to isolate the deferred failure.
Defensive patterns
Strategy: try-catch
Validate before calling
// Final construction validates cross-cutting invariants; pre-check the common ones
if base := cfg.GetString("baseURL"); base != "" {
if _, err := url.Parse(base); err != nil {
return fmt.Errorf("invalid baseURL: %w", err)
}
} Try / catch
conf, err := allconfig.LoadConfig(opts)
if err != nil {
// last-stage construction failure: individual sections decoded but the
// combined config is inconsistent (e.g. bad baseURL, conflicting language/output settings)
return err
} Prevention
- Treat this as a cross-section consistency failure: check baseURL, defaultContentLanguage vs languages, outputFormats/mediaTypes references
- Every custom output format must reference a defined media type and vice versa
- Run hugo config in CI to exercise the full construction path on every config change
- Fail the pipeline on any config error — never fall back to defaults silently
When it happens
Trigger: configs.transientErr() returning non-nil after fromLoadConfigResult succeeded — typically deferred per-language or cross-section validation failures recorded during construction of the per-language Config objects rather than raised immediately in a decoder.
Common situations: Cross-cutting config inconsistencies that only manifest once all languages/sections are assembled: per-language settings that individually parse but are jointly invalid, or deprecated/removed options recorded as deferred errors after a Hugo upgrade.
Related errors
- language name cannot be empty
- language name %q is invalid: %s
- default language %q is disabled
- defaultContentLanguage %q not found in languages configurati
- redirects must have either From or FromRe set
AI-assisted analysis of gohugoio/hugo@8a468df065 (2026-07-31).
Data as JSON: /data/errors/4ed1f9802841c484.json.
Report an issue: GitHub ↗.