gohugoio/hugo · error
failed to vendor module
Error message
failed to vendor module: %w
What it means
Returned by Client.Vendor when c.fs.Stat(sourceFilename) fails for a mount's source path inside the module directory. sourceFilename is filepath.Join(dir, mount.Source). The error is wrapped with %w so the underlying fs error (usually 'file does not exist') is unwrappable. This guards against declared mounts pointing at files/dirs that are not actually present in the dependency.
Solutions
- Check the wrapped error for the exact missing path, then verify that path exists in the module version you are pulling.
- Correct mount.Source in the module config to match the real directory/file name.
- Bump or pin the module to a version that contains the expected files.
- Remove mounts for paths you do not actually need.
Example fix
# before [[module.mounts]] source = "i18n" # directory no longer exists upstream target = "i18n" # after [[module.mounts]] source = "locales" target = "i18n"
Defensive patterns
Strategy: validation
Validate before calling
// Verify each mount source exists before vending.
func mountsExist(fs afero.Fs, dir string, mounts []Mount) error {
for _, mnt := range mounts {
if _, err := fs.Stat(filepath.Join(dir, mnt.Source)); err != nil {
return fmt.Errorf("mount source missing: %s: %w", mnt.Source, err)
}
}
return nil
} Try / catch
if err := client.Vendor(); err != nil {
if errors.Is(err, os.ErrNotExist) || strings.Contains(err.Error(), "failed to vendor module") {
// re-download module or fix mount.Source
}
} Prevention
- Keep mount.Source paths in sync with the module's real directory layout.
- Pin module versions whose file layout matches your mounts.
When it happens
Trigger: Running `hugo mod vendor` when a module's [[module.mounts]] source path does not exist on disk relative to the module's Dir(). Common when the mount source was renamed/removed in a newer module version but the consuming project pins an older config, or when a mount points to a path only present on a specific platform.
Common situations: Module author removed a directory (e.g. 'i18n') but a mount still references it; typo in mount.Source; a module pinned to a version that predates a directory the consuming project expects; vendoring after a partial git checkout of a module.
Related errors
- cannot vendor module
- could not determine content directory for
- failed to copy config dir to vendor dir
- failed to copy module file to vendor
- failed to copy module to vendor dir
AI-assisted analysis of gohugoio/hugo@52c9bd7908 (2026-08-09).
Data as JSON: /api/errors/b6e93879a1f0be91.
Report an issue: GitHub.
Appendix: 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 52c9bd7908)