gohugoio/hugo · error
failed to copy config dir to vendor dir
Error message
failed to copy config dir to vendor dir: %w
What it means
Returned by Client.Vendor when hugio.CopyDir fails copying the module's 'config' directory into _vendor, after Stat confirmed it exists. Wrapped with %w. This step mirrors the resources copy but for the module's top-level config folder, so module config travels with the vendored copy.
Solutions
- Inspect the wrapped error for the concrete OS failure.
- Repair permissions or broken symlinks in the module's config/ directory.
- Make _vendor writable and ensure free disk space.
- Re-download the module cleanly (`hugo mod clean` then vendor) if the cache is corrupted.
Example fix
# before hugo mod vendor # config/ copy fails # after hugo mod clean hugo mod vendor
Defensive patterns
Strategy: try-catch
Validate before calling
// Check the module's config dir is readable before vendoring.
func configDirReadable(fs afero.Fs, dir string) error {
cd := filepath.Join(dir, "config")
if _, err := fs.Stat(cd); err == nil {
f, err := fs.Open(cd)
if err != nil {
return err
}
f.Close()
}
return nil
} Try / catch
if err := client.Vendor(); err != nil {
if strings.Contains(err.Error(), "failed to copy config dir to vendor dir") {
// unwrap to find permission/symlink/space cause, fix, retry
}
} Prevention
- Keep module config/ directories free of platform-specific symlinks.
- Ensure _vendor is writable with adequate free space.
When it happens
Trigger: Running `hugo mod vendor` for a module that ships a 'config/' directory whose recursive copy fails for filesystem reasons (permissions, symlinks, disk space, read-only target).
Common situations: Module config dir containing platform-specific or symlinked files; restrictive permissions in the module cache; _vendor on a read-only mount; CI ephemeral filesystem limits.
Related errors
- failed to copy module file to vendor
- failed to copy module to vendor dir
- failed to copy resources to vendor dir
- failed to make target dir
- failed to copy to
AI-assisted analysis of gohugoio/hugo@52c9bd7908 (2026-08-09).
Data as JSON: /api/errors/35eb03c9fe5859ed.
Report an issue: GitHub.
Appendix: source
Thrown at modules/client.go:275
}
}
}
// 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 {
return fmt.Errorf("failed to copy config dir to vendor dir: %w", err)
}
}
// Also include any theme.toml or config.* or hugo.* files in the root.
configFiles, _ := afero.Glob(c.fs, filepath.Join(dir, "config.*"))
configFiles2, _ := afero.Glob(c.fs, filepath.Join(dir, "hugo.*"))
configFiles = append(configFiles, configFiles2...)
configFiles = append(configFiles, filepath.Join(dir, "theme.toml"))
for _, configFile := range configFiles {
if err := hugio.CopyFile(c.fs, configFile, filepath.Join(vendorDir, t.PathVersionQuery(true), filepath.Base(configFile))); err != nil {
if !herrors.IsNotExist(err) {
return err
}
}
}
}
if modulesContent.Len() > 0 {View on GitHub (pinned to 52c9bd7908)