gohugoio/hugo · error

failed to vendor module: %w

Error message

failed to vendor module: %w

What it means

During `hugo mod vendor` (modules/client.go:241), Hugo stats each mount's source path (module dir + mount source) before copying it into _vendor/. If the stat fails — usually because the mounted path doesn't exist on disk — vendoring aborts with the wrapped filesystem error.

Source

Thrown at modules/client.go:241

			continue
		}

		// See https://github.com/gohugoio/hugo/issues/8239
		// This is an error situation. We need something to vendor.
		if t.Mounts() == nil {
			return fmt.Errorf("cannot vendor module %q, need at least one mount", t.PathVersionQuery(false))
		}

		fmt.Fprintln(&modulesContent, "# "+t.PathVersionQuery(true)+" "+t.Version())

		dir := t.Dir()

		for _, mount := range t.Mounts() {
			sourceFilename := filepath.Join(dir, mount.Source)
			targetFilename := filepath.Join(vendorDir, t.PathVersionQuery(true), mount.Source)
			fi, err := c.fs.Stat(sourceFilename)
			if err != nil {
				return fmt.Errorf("failed to vendor module: %w", err)
			}

			if fi.IsDir() {
				if err := hugio.CopyDir(c.fs, sourceFilename, targetFilename, nil); err != nil {
					return fmt.Errorf("failed to copy module to vendor dir: %w", err)
				}
			} else {
				targetDir := filepath.Dir(targetFilename)

				if err := c.fs.MkdirAll(targetDir, 0o755); err != nil {
					return fmt.Errorf("failed to make target dir: %w", err)
				}

				if err := hugio.CopyFile(c.fs, sourceFilename, targetFilename); err != nil {
					return fmt.Errorf("failed to copy module file to vendor: %w", err)
				}
			}
		}

View on GitHub ↗ (pinned to 8a468df065)

Solutions

  1. Read the wrapped error to get the missing path, then check whether that directory exists in the module's source (see hugo mod graph for the cache dir, or the upstream repo).
  2. Fix or remove the mount entry referencing the nonexistent path in the module's (or project's per-import) config.
  3. Run hugo mod clean && hugo mod get -u to refresh a possibly corrupt module cache.
  4. Pin the dependency to a version where the directory still exists.
Defensive patterns

Strategy: try-catch

Validate before calling

// Check the vendor destination is writable before vendoring
vendorDir := filepath.Join(workingDir, "_vendor")
if err := os.MkdirAll(vendorDir, 0o755); err != nil {
    return fmt.Errorf("cannot create vendor dir: %w", err)
}

Type guard

func isVendorErr(err error) bool {
    return err != nil && strings.Contains(err.Error(), "failed to vendor module")
}

Try / catch

if err := client.Vendor(); err != nil {
    if errors.Is(err, fs.ErrPermission) {
        return fmt.Errorf("vendor dir not writable: %w", err)
    }
    return fmt.Errorf("vendoring failed, _vendor may be partial — delete it and retry: %w", err)
}

Prevention

When it happens

Trigger: c.fs.Stat(filepath.Join(t.Dir(), mount.Source)) returns an error while iterating a module's mounts in Client.Vendor(). Happens when a mount declares a source directory/file that is missing from the downloaded module.

Common situations: A module config mounting a directory that was renamed or deleted upstream; version bump of a dependency that removed a directory still referenced by mounts; stale module cache; case-sensitivity mismatches between macOS/Windows dev and Linux CI.

Related errors


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