gohugoio/hugo · critical

no modules loaded (need at least the main module)

Error message

no modules loaded (need at least the main module)

What it means

After collecting modules, Hugo's config Init requires at least the main module. If c.Modules is empty, initialization aborts with this error. It typically means the working directory is not a valid Hugo project (no config file resolved and/or no go.mod/module graph) so module loading produced nothing.

Solutions

  1. Run hugo from the project root that contains the config file (hugo.toml/yaml/json).
  2. Run `hugo mod init github.com/me/site` to establish the main module.
  3. Verify the `module` config block and theme/module paths resolve; check earlier log lines for module load warnings.

Example fix

// before: run from a subfolder with no config
hugo
// after
hugo mod init github.com/me/site
hugo server   # from project root
Defensive patterns

Strategy: validation

Validate before calling

// Before building, ensure a config file resolves in the working dir
if _, err := os.Stat(filepath.Join(workDir, "hugo.toml")); err != nil {
    return fmt.Errorf("no Hugo config in %s; run `hugo new site .` or `hugo mod init`", workDir)
}

Try / catch

cfg, err := allconfig.LoadConfig(d)
if err != nil {
    if strings.Contains(err.Error(), "no modules loaded") {
        // prompt user to scaffold/init the module, then retry
    }
    return err
}

Prevention

When it happens

Trigger: Running hugo from a directory with no resolvable config and no module information, or after module collection silently returned an empty set due to import failures.

Common situations: Wrong working directory (running from a subfolder); `hugo mod init` never run so there is no main module; broken module imports or a themesDir/content mount that prevents the main module from registering; CI running in the wrong checkout path.

Related errors


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

Appendix: source

Thrown at config/allconfig/allconfig.go:958

		for _, s := range allDecoderSetups {
			if getInitializer := s.getInitializer; getInitializer != nil {
				if err := getInitializer(langConfig).InitConfig(logger, nil, c.ConfiguredDimensions); err != nil {
					return err
				}
			}
		}

		c.configLangs[i] = ConfigLanguage{
			m:             c,
			config:        langConfig,
			baseConfig:    c.LoadingInfo.BaseConfig,
			language:      l,
			languageIndex: i,
		}
	}

	if len(c.Modules) == 0 {
		return errors.New("no modules loaded (need at least the main module)")
	}

	// Apply default project mounts.
	if err := modules.ApplyProjectConfigDefaults(logger.Logger(), c.Modules[0], c.configLangs...); err != nil {
		return err
	}

	// We should consolidate this, but to get a full view of the mounts in e.g. "hugo config" we need to
	// transfer any default mounts added above to the config used to print the config.
	for _, m := range c.Modules[0].Mounts() {
		var found bool
		for _, cm := range c.Base.Module.Mounts {
			if cm.Equal(m) {
				found = true
				break
			}
		}
		if !found {

View on GitHub (pinned to 52c9bd7908)