{"record":{"id":"a58d4083dc9ee199","repo":"golangci/golangci-lint","slug":"hash-plugin-directory-w","errorCode":null,"errorMessage":"hash plugin directory: %w","messagePattern":"hash plugin directory: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/commands/internal/builder.go","lineNumber":263,"sourceCode":"\tname := b.cfg.Name\n\tif runtime.GOOS == \"windows\" {\n\t\tname += \".exe\"\n\t}\n\n\treturn name\n}\n\nfunc (b Builder) createVersion(orig string) (string, error) {\n\thash := sha256.New()\n\n\tfor _, plugin := range b.cfg.Plugins {\n\t\tif plugin.Path == \"\" {\n\t\t\tcontinue\n\t\t}\n\n\t\tdh, err := hashDir(plugin.Path, \"\", dirhash.DefaultHash)\n\t\tif err != nil {\n\t\t\treturn \"\", fmt.Errorf(\"hash plugin directory: %w\", err)\n\t\t}\n\n\t\tb.log.Infof(\"%s: %s\", plugin.Path, dh)\n\n\t\thash.Write([]byte(dh))\n\t}\n\n\treturn fmt.Sprintf(\"%s-custom-gcl-%s\",\n\t\tsanitizeVersion(orig),\n\t\tsanitizeVersion(base64.URLEncoding.EncodeToString(hash.Sum(nil))),\n\t), nil\n}\n\nfunc sanitizeVersion(v string) string {\n\tfn := func(c rune) bool {\n\t\treturn !unicode.IsLetter(c) && !unicode.IsNumber(c) && c != '.' && c != '/'\n\t}\n","sourceCodeStart":245,"sourceCodeEnd":281,"githubUrl":"https://github.com/golangci/golangci-lint/blob/ed7a235d2d771152056fdc142a9855567c5796a9/pkg/commands/internal/builder.go#L245-L281","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\nplugins:\n  - path: ./plugins/myplugin   # never cloned\n// after\ngit submodule update --init --recursive\n# or fix path:\nplugins:\n  - path: ../shared/myplugin","handlingStrategy":"validation","validationCode":"for _, plugin := range cfg.Plugins {\n    if plugin.Path == \"\" { continue }\n    fi, err := os.Stat(plugin.Path)\n    if err != nil {\n        return fmt.Errorf(\"plugin dir %s missing (init submodules?): %w\", plugin.Path, err)\n    }\n    if !fi.IsDir() {\n        return fmt.Errorf(\"plugin path %s is not a directory\", plugin.Path)\n    }\n}","typeGuard":null,"tryCatchPattern":"dh, err := hashDir(plugin.Path, \"\", dirhash.DefaultHash)\nif err != nil {\n    var perr *fs.PathError\n    if errors.As(err, &perr) {\n        log.Fatalf(\"cannot hash plugin %s: %v — restore the checkout (git submodule update --init --recursive) or fix the configured path\", plugin.Path, perr.Err)\n    }\n    return err\n}","preventionTips":["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"],"tags":["go","hash","directory","plugins","config"],"backgroundTag":"directory-not-found","analyzedSha":"ed7a235d2d771152056fdc142a9855567c5796a9","analyzedAt":"2026-09-02T18:47:33.865Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}