hashicorp/nomad · error
failed to open plugin directory %q: %v
Error message
failed to open plugin directory %q: %v
What it means
During scan, the loader opens the configured plugin_dir to enumerate external plugin files. If os.Open fails with an error other than not-exist (which is only logged and skipped), this error wraps it — typically a permissions problem or the path being a non-directory.
Source
Thrown at helper/pluginutils/loader/init.go:238
return converted, nil
}
// scan scans the plugin directory and retrieves potentially eligible binaries
func (l *PluginLoader) scan() ([]os.FileInfo, error) {
if l.pluginDir == "" {
return nil, nil
}
// Capture the list of binaries in the plugins folder
f, err := os.Open(l.pluginDir)
if err != nil {
// There are no plugins to scan
if os.IsNotExist(err) {
l.logger.Warn("skipping external plugins since plugin_dir doesn't exist")
return nil, nil
}
return nil, fmt.Errorf("failed to open plugin directory %q: %v", l.pluginDir, err)
}
files, err := f.Readdirnames(-1)
f.Close()
if err != nil {
return nil, fmt.Errorf("failed to read plugin directory %q: %v", l.pluginDir, err)
}
var plugins []os.FileInfo
for _, f := range files {
f = filepath.Join(l.pluginDir, f)
s, err := os.Stat(f)
if err != nil {
return nil, fmt.Errorf("failed to stat file %q: %v", f, err)
}
if s.IsDir() {
l.logger.Warn("skipping subdir in plugin folder", "subdir", f)
continue
}View on GitHub (pinned to 482b49bf1a)
Solutions
- Fix permissions so the Nomad agent user can read the plugin_dir (chmod/chown or run the agent with sufficient privileges)
- Verify plugin_dir in the agent config points to an existing directory, not a file
- Create the directory if it was deleted (os.MkdirAll) — note a missing dir is tolerated, but an unreadable existing path is not
Example fix
# before (agent config) plugin_dir = "/etc/nomad-plugins.txt" # after plugin_dir = "/etc/nomad-plugins"
Defensive patterns
Strategy: validation
Validate before calling
info, err := os.Stat(cfg.PluginDir)
if err != nil {
return fmt.Errorf("plugin_dir %q: %w", cfg.PluginDir, err)
}
if !info.IsDir() {
return fmt.Errorf("plugin_dir %q is not a directory", cfg.PluginDir)
}
if f, err := os.Open(cfg.PluginDir); err != nil {
return fmt.Errorf("plugin_dir %q not readable: %w", cfg.PluginDir, err)
} else { f.Close() } Try / catch
if err := loader.Init(...); err != nil {
if strings.Contains(err.Error(), "failed to open plugin directory") {
// check permissions/ownership of plugin_dir and that it's a directory
}
} Prevention
- Create plugin_dir at install time with correct ownership for the agent user
- Point plugin_dir at a directory, never a file or symlink to a file
- Verify the path is mounted/present in containerized deployments before starting the agent
- Run Nomad's config validation (nomad agent -config-check style validation) before launch
When it happens
Trigger: init -> scan with l.pluginDir pointing to a path that exists but cannot be opened: bad permissions, path is a file not a directory, mount unavailable, or an OS-level I/O error (anything other than fs.ErrNotExist).
Common situations: plugin_dir set in the Nomad agent config to a path owned by another user; docker/k8s volume not mounted; plugin_dir pointed at a file instead of a directory.
Related errors
- plugin not executable
- Chmod(%v) failed: %w
- Couldn't change owner/group of %v to (uid: %v, gid: %v): %w
- unable to remove existing unix socket: %w
- failed to create secrets/envoy_bootstrap.json for envoy: %w
AI-assisted analysis of hashicorp/nomad@482b49bf1a (2026-09-04).
Data as JSON: /api/errors/21ff8410f7d2fd66.
Report an issue: GitHub.