gohugoio/hugo · error

invalid module config for

Error message

invalid module config for %q: both source and target must be set

What it means

Returned by collector.normalizeMounts in modules/collect.go:800 when a module mount has an empty Source or Target. Mounts map a source path into Hugo's virtual filesystem; both ends are mandatory. The error names the offending module (owner.Path()).

Solutions

  1. Find the mount flagged by the module name in the error and add the missing source and target.
  2. Ensure source is a non-empty path relative to the module dir and target is a Hugo filesystem dir (e.g. static, content, layouts, assets, archetypes, i18n, data).
  3. Run `hugo config` to print resolved mounts and spot the blank entry.

Example fix

// before
[[module.mounts]]
source = "content"
// after
[[module.mounts]]
source = "content"
target = "content"
Defensive patterns

Strategy: validation

Validate before calling

// Validate every mount has both fields before collection.
for _, m := range mounts {
    if m.Source == "" || m.Target == "" { return errors.New("mount missing source/target") }
}

Prevention

When it happens

Trigger: Declaring [[module.mounts]] with source or target omitted/blank, in either the project config or a theme/module's config. normalizeMounts runs during module collection for every mount of every active module.

Common situations: A typo'd [[module.mounts]] table missing a key, a config merge that dropped a field, or a theme upgrade whose mounts schema expects a field the project didn't supply.

Related errors


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

Appendix: source

Thrown at modules/collect.go:800

		return s
	}
	if strings.HasPrefix(s, "../../node_modules/") {
		// See #14083. This was a common construct to mount node_modules from the project root.
		// This started failing in v0.152.0 when we tightened the validation.
		return strings.TrimPrefix(s, "../../")
	}
	return ""
}

func (c *collector) normalizeMounts(owner *moduleAdapter, mounts []Mount) ([]Mount, error) {
	var out []Mount
	dir := owner.Dir()

	for _, mnt := range mounts {
		errMsg := fmt.Sprintf("invalid module config for %q", owner.Path())

		if mnt.Source == "" || mnt.Target == "" {
			return nil, errors.New(errMsg + ": both source and target must be set")
		}

		// Special case for node_modules imports in themes/modules.
		// See #14089.
		var isModuleNodeModulesImport bool
		if !owner.projectMod {
			nodeModulesImportSource := c.nodeModulesRoot(mnt.Source)
			if nodeModulesImportSource != "" {
				isModuleNodeModulesImport = true
				mnt.Source = nodeModulesImportSource
			}
		}

		mnt.Source = filepath.Clean(mnt.Source)
		mnt.Target = filepath.Clean(mnt.Target)
		var sourceDir string

		if !owner.projectMod && !filepath.IsLocal(mnt.Source) {

View on GitHub (pinned to 52c9bd7908)