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

  1. Read the wrapped transient error text — it describes the actual invalid setting; fix that key in your config.
  2. Check per-language override blocks ([languages.xx.*]) for values inconsistent with root config.
  3. After a Hugo upgrade, run `hugo config` and review the release notes for options that became errors.
  4. 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

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


AI-assisted analysis of gohugoio/hugo@8a468df065 (2026-07-31). Data as JSON: /data/errors/4ed1f9802841c484.json. Report an issue: GitHub ↗.