gohugoio/hugo · error

failed to load config: %w

Error message

failed to load config: %w

What it means

Wrap returned when l.loadConfigMain fails — the phase that locates, parses and merges the main config file(s), config/ directory, environment overrides and theme configs. It wraps the concrete cause (TOML/YAML/JSON parse error, ErrNoConfigFile, an invalid environment override, a failing section decoder) with a generic 'failed to load config' prefix.

Source

Thrown at config/allconfig/load.go:68

		}
	}()

	if len(d.Environ) == 0 && !hugo.IsRunningAsTest() {
		d.Environ = os.Environ()
	}

	if d.Logger == nil {
		d.Logger = loggers.NewDefault()
	}

	l := &configLoader{ConfigSourceDescriptor: d, cfg: config.New()}
	// Make sure we always do this, even in error situations,
	// as we have commands (e.g. "hugo mod init") that will
	// use a partial configuration to do its job.
	defer l.deleteMergeStrategies()
	res, _, err := l.loadConfigMain(d)
	if err != nil {
		return nil, fmt.Errorf("failed to load config: %w", err)
	}

	configs, err = fromLoadConfigResult(d.Fs, d.Logger, res)
	if err != nil {
		return nil, fmt.Errorf("failed to create config from result: %w", err)
	}

	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)

View on GitHub ↗ (pinned to 8a468df065)

Solutions

  1. Read the wrapped inner error — it usually includes the file name and line/column of the parse failure; fix that syntax.
  2. Validate the config file with a TOML/YAML linter matching its extension.
  3. Unset or fix HUGO_* environment variables if the error appears only in one environment (compare `env | grep HUGO`).
  4. If using a config/ directory, check every file in config/_default/ and the active environment directory parses on its own.

Example fix

# before (hugo.toml — unclosed string)
title = "My Site
baseURL = 'https://example.org/'
# after
title = "My Site"
baseURL = 'https://example.org/'
Defensive patterns

Strategy: try-catch

Validate before calling

// If loading from a config dir, verify it exists and is a directory
fi, err := os.Stat(configDir)
if err != nil || !fi.IsDir() {
    return fmt.Errorf("config dir %q missing or not a directory", configDir)
}

Try / catch

conf, err := allconfig.LoadConfig(opts)
if err != nil {
    var fe herrors.FileError
    if errors.As(err, &fe) {
        // file/line available — show it, don't swallow
    }
    return err
}

Prevention

When it happens

Trigger: Syntax errors in hugo.toml/hugo.yaml/hugo.json or files under config/_default/; duplicate TOML keys; a HUGO_* environment variable that fails to parse into the expected type; a section decoder from alldecoders.go returning an error during the main merge pass; unreadable config files (permissions).

Common situations: A stray character or unclosed quote after hand-editing config; mixing tabs/spaces in YAML config; CI setting HUGO_PARAMS_* env vars with malformed values; splitting config into config/_default/*.toml and introducing a duplicate or misnamed file.

Related errors


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