{"record":{"id":"331eccfc2658a521","repo":"hashicorp/nomad","slug":"failed-to-stat-file-q-v","errorCode":null,"errorMessage":"failed to stat file %q: %v","messagePattern":"failed to stat file %q: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"helper/pluginutils/loader/init.go","lineNumber":251,"sourceCode":"\t\tif os.IsNotExist(err) {\n\t\t\tl.logger.Warn(\"skipping external plugins since plugin_dir doesn't exist\")\n\t\t\treturn nil, nil\n\t\t}\n\n\t\treturn nil, fmt.Errorf(\"failed to open plugin directory %q: %v\", l.pluginDir, err)\n\t}\n\tfiles, err := f.Readdirnames(-1)\n\tf.Close()\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to read plugin directory %q: %v\", l.pluginDir, err)\n\t}\n\n\tvar plugins []os.FileInfo\n\tfor _, f := range files {\n\t\tf = filepath.Join(l.pluginDir, f)\n\t\ts, err := os.Stat(f)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to stat file %q: %v\", f, err)\n\t\t}\n\t\tif s.IsDir() {\n\t\t\tl.logger.Warn(\"skipping subdir in plugin folder\", \"subdir\", f)\n\t\t\tcontinue\n\t\t}\n\n\t\tif !executable(f, s) {\n\t\t\tl.logger.Warn(\"skipping un-executable file in plugin folder\", \"file\", f)\n\t\t\tcontinue\n\t\t}\n\t\tplugins = append(plugins, s)\n\t}\n\n\treturn plugins, nil\n}\n\n// fingerprintPlugins fingerprints all external plugin binaries\nfunc (l *PluginLoader) fingerprintPlugins(plugins []os.FileInfo, configs map[string]*config.PluginConfig) (map[PluginID]*pluginInfo, error) {","sourceCodeStart":233,"sourceCodeEnd":269,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/helper/pluginutils/loader/init.go#L233-L269","documentation":"In scan(), after listing directory entry names, each entry is joined with pluginDir and passed to os.Stat to get FileInfo. This error is returned when os.Stat fails for a specific file, wrapping the OS error. It means an entry listed in the plugin directory could not be stat'd, usually a race (file deleted between listing and stat) or a permission problem.","triggerScenarios":"os.Stat(f) returns an error for an entry in plugin_dir: dangling symlink (target removed after Readdirnames), file deleted concurrently, execute/read permission denied on parent path components, or overly long path names.","commonSituations":"Broken symlinks left in plugin_dir pointing to uninstalled plugin binaries; plugin upgrade script removing files while Nomad agent is starting; plugin dir containing entries the nomad user cannot traverse; immutable/locked files on Windows.","solutions":["Inspect the wrapped %v OS error to identify which file and why (e.g. 'no such file or directory' = dangling symlink/race).","Remove broken symlinks or stale entries from plugin_dir.","Ensure the Nomad agent user has read+execute (traverse) permission on plugin_dir and every path component.","Avoid mutating plugin_dir while the agent starts; perform plugin installs/upgrades with the agent stopped or atomically (write-then-rename).","Restart the agent and confirm plugins fingerprint."],"exampleFix":"// before: broken symlink in plugin dir\n/opt/nomad-plugins/docker -> /usr/local/bin/docker-plugin-removed\n// after\nrm /opt/nomad-plugins/docker  # then restart the agent","handlingStrategy":"validation","validationCode":"// audit plugin_dir for un-stat-able entries before agent start\nentries, _ := os.ReadDir(pluginDir)\nfor _, e := range entries {\n\tp := filepath.Join(pluginDir, e.Name())\n\tif _, err := os.Stat(p); err != nil {\n\t\tlog.Printf(\"removing unstat-able plugin entry %s: %v\", p, err)\n\t\tos.Remove(p)\n\t}\n}","typeGuard":null,"tryCatchPattern":"// Go: surface the wrapped PathError per-file\nif _, err := os.Stat(path); err != nil {\n\tvar perr *os.PathError\n\tif errors.As(err, &perr) && errors.Is(perr.Err, fs.ErrNotExist) {\n\t\t// dangling symlink or raced delete: clean up and rescan\n\t}\n}","preventionTips":["Periodically clean broken symlinks from plugin_dir.","Install/upgrade plugins atomically (write to temp file, rename) or with the agent stopped.","Grant the nomad service user traverse (x) permission on all parent directories of plugin_dir.","Avoid scripts that delete-and-recreate files in plugin_dir while the agent runs."],"tags":["filesystem","plugin-loader","nomad","os-stat"],"backgroundTag":"file-not-found","analyzedSha":"482b49bf1aec006f089bcfc7e632d8f6ac303e5e","analyzedAt":"2026-09-04T07:54:14.808Z","contentChangedAt":"2026-09-04T07:54:14.808Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}