golangci/golangci-lint · error
hash plugin directory: %w
Error message
hash plugin directory: %w
What it means
createVersion computes a deterministic version hash by hashing each configured plugin's directory with hashDir(plugin.Path, "", dirhash.DefaultHash). This error wraps a hashDir failure, meaning the plugin directory could not be read or hashed (module dirhash requires reading all files). It aborts version computation for the build.
Source
Thrown at pkg/commands/internal/builder.go:263
name := b.cfg.Name
if runtime.GOOS == "windows" {
name += ".exe"
}
return name
}
func (b Builder) createVersion(orig string) (string, error) {
hash := sha256.New()
for _, plugin := range b.cfg.Plugins {
if plugin.Path == "" {
continue
}
dh, err := hashDir(plugin.Path, "", dirhash.DefaultHash)
if err != nil {
return "", fmt.Errorf("hash plugin directory: %w", err)
}
b.log.Infof("%s: %s", plugin.Path, dh)
hash.Write([]byte(dh))
}
return fmt.Sprintf("%s-custom-gcl-%s",
sanitizeVersion(orig),
sanitizeVersion(base64.URLEncoding.EncodeToString(hash.Sum(nil))),
), nil
}
func sanitizeVersion(v string) string {
fn := func(c rune) bool {
return !unicode.IsLetter(c) && !unicode.IsNumber(c) && c != '.' && c != '/'
}
View on GitHub (pinned to ed7a235d2d)
Solutions
- Verify each plugin.Path exists and is a directory (ls <plugin.Path>) as configured
- Initialize missing submodules/vendored deps: git submodule update --init --recursive
- Fix the plugin path in configuration or restore the plugin checkout at the expected location
- Check read permissions on the plugin directory and its files
- The wrapped error names the specific file that failed — open/read that path directly to pinpoint the cause
Example fix
// before plugins: - path: ./plugins/myplugin # never cloned // after git submodule update --init --recursive # or fix path: plugins: - path: ../shared/myplugin
Defensive patterns
Strategy: validation
Validate before calling
for _, plugin := range cfg.Plugins {
if plugin.Path == "" { continue }
fi, err := os.Stat(plugin.Path)
if err != nil {
return fmt.Errorf("plugin dir %s missing (init submodules?): %w", plugin.Path, err)
}
if !fi.IsDir() {
return fmt.Errorf("plugin path %s is not a directory", plugin.Path)
}
} Try / catch
dh, err := hashDir(plugin.Path, "", dirhash.DefaultHash)
if err != nil {
var perr *fs.PathError
if errors.As(err, &perr) {
log.Fatalf("cannot hash plugin %s: %v — restore the checkout (git submodule update --init --recursive) or fix the configured path", plugin.Path, perr.Err)
}
return err
} Prevention
- git submodule update --init --recursive after every fresh clone or branch switch
- Validate all plugin.Path entries exist before starting the version/build step
- Keep plugin paths in config relative to the repo root and correct after moving directories
- Ensure CI checkouts are full (not sparse/partial) for directories being hashed
When it happens
Trigger: A plugin entry in the configuration has a non-empty Path but the directory is missing, unreadable, or contains unreadable files; hashDir walks the tree and fails on open/read/stat of any file, or the path is a file rather than a directory.
Common situations: Plugin checked out at a tag/branch that no longer exists after switching versions, submodule not initialized (plugins/vendor/empty), path typo in config, or checkout on CI with sparse/partial clone excluding the plugin directory.
Related errors
AI-assisted analysis of golangci/golangci-lint@ed7a235d2d (2026-09-02).
Data as JSON: /api/errors/a58d4083dc9ee199.
Report an issue: GitHub.