gohugoio/hugo · error

failed to copy module to vendor dir: %w

Error message

failed to copy module to vendor dir: %w

What it means

In `hugo mod vendor` (modules/client.go:246), when a mount source is a directory, Hugo recursively copies it into _vendor/<module-path>/ via hugio.CopyDir. Any I/O failure during that recursive copy surfaces as this wrapped error and aborts vendoring.

Source

Thrown at modules/client.go:246

		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)
				}
			}
		}

		// Include the resource cache if present.
		resourcesDir := filepath.Join(dir, files.FolderResources)
		_, err := c.fs.Stat(resourcesDir)
		if err == nil {

View on GitHub ↗ (pinned to 8a468df065)

Solutions

  1. Check the wrapped error for the failing path and whether it's a read (source) or write (target) failure.
  2. Ensure the project directory is writable and has free disk space; delete a partially written _vendor and retry.
  3. Fix permissions on the module cache (go clean -modcache then re-download if it's corrupted).
  4. On Windows, exclude the project from real-time AV scanning while vendoring.
Defensive patterns

Strategy: try-catch

Validate before calling

// Confirm the module source dir exists and is readable
if fi, err := os.Stat(mod.Dir()); err != nil || !fi.IsDir() {
    return fmt.Errorf("module dir %q not accessible: %v", mod.Dir(), err)
}

Try / catch

if err := client.Vendor(); err != nil {
    if strings.Contains(err.Error(), "failed to copy module to vendor dir") {
        // usually a filesystem issue: permissions, symlinks, or missing module cache
        return fmt.Errorf("run 'hugo mod download' first, then re-vendor: %w", err)
    }
    return err
}

Prevention

When it happens

Trigger: hugio.CopyDir(c.fs, sourceFilename, targetFilename, nil) fails while copying a mounted directory tree — permission errors, unreadable files, disk full, or files disappearing mid-copy.

Common situations: Read-only or root-owned files inside the Go module cache (GOMODCACHE stores modules read-only, though reads normally suffice); no write permission or no space in the project's _vendor directory; antivirus/file-lock interference on Windows; symlinks or special files inside the mounted tree.

Related errors


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