hashicorp/nomad · error
failed to scan plugin directory %q: %v
Error message
failed to scan plugin directory %q: %v
What it means
After initializing internal plugins, the loader calls scan() to walk l.pluginDir for eligible plugin binaries. If that filesystem scan fails (unreadable directory, permission denied, stat errors), init wraps the error with the plugin directory path in this message.
Source
Thrown at helper/pluginutils/loader/init.go:70
return mErr.ErrorOrNil()
}
// init initializes the plugin loader by compiling both internal and external
// plugins and selecting the highest versioned version of any given plugin.
func (l *PluginLoader) init(cfg *PluginLoaderConfig) (map[string]*config.PluginConfig, error) {
// Create a mapping of name to config
configMap := configMap(cfg.Configs)
// Initialize the internal plugins
internal, err := l.initInternal(cfg.InternalPlugins, configMap)
if err != nil {
return nil, fmt.Errorf("failed to fingerprint internal plugins: %v", err)
}
// Scan for eligibile binaries
plugins, err := l.scan()
if err != nil {
return nil, fmt.Errorf("failed to scan plugin directory %q: %v", l.pluginDir, err)
}
// Fingerprint the passed plugins
external, err := l.fingerprintPlugins(plugins, configMap)
if err != nil {
return nil, fmt.Errorf("failed to fingerprint plugins: %v", err)
}
// Merge external and internal plugins
l.plugins = l.mergePlugins(internal, external)
// Validate that the configs are valid for the plugins
canonicalizedConfigs, err := l.validatePluginConfigs()
if err != nil {
return nil, fmt.Errorf("parsing plugin configurations failed: %v", err)
}
for i := range configMap {View on GitHub (pinned to 482b49bf1a)
Solutions
- Check that the directory in the error message exists: ls <dir>.
- Fix permissions: chmod/chown the directory so the process user can read and traverse it.
- Correct the PluginDir value in the loader config.
- In containers, ensure the plugins volume is mounted and the path is created in the image.
Example fix
// before
cfg := &PluginLoaderConfig{PluginDir: "/opt/nomad-plugins-missing", ...}
// after
if _, err := os.Stat(pluginDir); err != nil {
return fmt.Errorf("plugin dir unavailable: %w", err)
}
cfg := &PluginLoaderConfig{PluginDir: pluginDir, ...} Defensive patterns
Strategy: validation
Validate before calling
info, err := os.Stat(cfg.PluginDir)
if err != nil || !info.IsDir() {
return fmt.Errorf("plugin dir %q missing or not a directory", cfg.PluginDir)
}
if err := unix.Access(cfg.PluginDir, unix.R_OK|unix.X_OK); err != nil {
return fmt.Errorf("plugin dir %q not readable: %w", cfg.PluginDir, err)
} Try / catch
loader, err := NewPluginLoader(cfg)
if err != nil {
if strings.Contains(err.Error(), "failed to scan plugin directory") {
return fmt.Errorf("check plugin dir existence/permissions: %w", err)
}
return err
} Prevention
- Create the plugin directory in image/entrypoint before starting the app.
- Verify volume mounts in container orchestration configs.
- Run the service as a user with read+execute on the plugin dir.
- Log the resolved PluginDir at startup for easier diagnosis.
When it happens
Trigger: PluginDir points to a nonexistent path; the process lacks read/execute permission on the directory; the path is a file, not a directory; an FS error occurs while walking entries.
Common situations: Container images where the plugin dir wasn't created or mounted; running the app as a non-root user after plugins were installed as root with restrictive modes; typo'd path in config; bind mount missing in Kubernetes/Docker.
Related errors
- error creating directory: %w
- error setting directory permission mode: %w
- cannot create copy - %s
- failed to open plugin directory %q: %v
- failed to open snapshot dir: %v
AI-assisted analysis of hashicorp/nomad@482b49bf1a (2026-09-04).
Data as JSON: /api/errors/7fec4be281d19d15.
Report an issue: GitHub.