gohugoio/hugo · error

failed to copy module file to vendor

Error message

failed to copy module file to vendor: %w

What it means

Returned by Client.Vendor when hugio.CopyFile fails copying a single-file mount's source to the vendor target (after the target dir was successfully created). Wrapped with %w. Indicates the source file became inaccessible between Stat and CopyFile, or the target write was rejected.

Solutions

  1. Inspect the wrapped error to distinguish read failure (source) from write failure (target).
  2. Re-run `hugo mod vendor` after stopping concurrent module downloads.
  3. Fix source read permissions or the target write permissions.
  4. Clear the module cache and re-download: `hugo mod clean` then vendor again.

Example fix

# before: cache file unreadable
hugo mod vendor   # CopyFile fails

# after
hugo mod clean
hugo mod vendor
Defensive patterns

Strategy: try-catch

Validate before calling

// Verify read access on source files and write access on target.
func copyable(fs afero.Fs, src, dst string) error {
    f, err := fs.Open(src)
    if err != nil {
        return err
    }
    f.Close()
    return fs.MkdirAll(filepath.Dir(dst), 0o755)
}

Try / catch

if err := client.Vendor(); err != nil {
    if strings.Contains(err.Error(), "failed to copy module file to vendor") {
        // re-download module and retry; race or transient read failure
    }
}

Prevention

When it happens

Trigger: Running `hugo mod vendor` for a file-type mount where CopyFile returns an error: source removed/unreadable mid-copy, target path not writable, or afero write rejection. The earlier Stat (452 path) succeeded, so this is a transient or write-side failure.

Common situations: Concurrent process modifying the module cache (e.g. `go mod download` racing with vendor); a file with no read permission even though the dir Stat passed; target disk full; antivirus/SELinux blocking the write.

Related errors


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

Appendix: source

Thrown at modules/client.go:256

			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 {
			if err := hugio.CopyDir(c.fs, resourcesDir, filepath.Join(vendorDir, t.PathVersionQuery(true), files.FolderResources), nil); err != nil {
				return fmt.Errorf("failed to copy resources to vendor dir: %w", err)
			}
		}

		// Include the config directory if present.
		configDir := filepath.Join(dir, "config")
		_, err = c.fs.Stat(configDir)
		if err == nil {
			if err := hugio.CopyDir(c.fs, configDir, filepath.Join(vendorDir, t.PathVersionQuery(true), "config"), nil); err != nil {

View on GitHub (pinned to 52c9bd7908)