hashicorp/nomad · error
ErrPluginNotExecutable
ErrPluginNotExecutable
Error message
plugin not executable
What it means
ErrPluginNotExecutable indicates that an external plugin binary (host volume or secrets plugin) was found on disk but does not have the executable bit set. Nomad refuses to launch plugins that lack the executable permission, as they cannot be executed as subprocesses. It is typically wrapped with fmt.Errorf to include the plugin name.
Source
Thrown at client/hostvolumemanager/host_volumes.go:22
package hostvolumemanager
import (
"context"
"errors"
"fmt"
"os"
"sync"
"github.com/hashicorp/go-hclog"
"github.com/hashicorp/go-multierror"
cstructs "github.com/hashicorp/nomad/client/structs"
"github.com/hashicorp/nomad/helper"
"github.com/hashicorp/nomad/nomad/structs"
)
var (
ErrPluginNotExists = errors.New("no such plugin")
ErrPluginNotExecutable = errors.New("plugin not executable")
ErrVolumeNameExists = errors.New("volume name already exists on this node")
)
// HostVolumeStateManager manages the lifecycle of volumes in client state.
type HostVolumeStateManager interface {
PutDynamicHostVolume(*cstructs.HostVolumeState) error
GetDynamicHostVolumes() ([]*cstructs.HostVolumeState, error)
DeleteDynamicHostVolume(string) error
}
// Config is used to configure a HostVolumeManager.
type Config struct {
// PluginDir is where external plugins may be found.
PluginDir string
// VolumesDir is where plugins should place the directory
// that will later become a volume's HostPath
VolumesDir stringView on GitHub (pinned to 482b49bf1a)
Solutions
- chmod +x the plugin binary inside the configured plugin_dir
- Re-download/re-extract the plugin preserving permissions (tar -xzf keeps modes)
- Verify the configured path points at the binary itself, not a data or README file
- Add an install step (e.g. install -m 0755 plugin /path) in provisioning
Example fix
// before $ cp nomad-volume-plugin /opt/nomad/plugins/ # mode 0644 -> "plugin not executable" // after $ install -m 0755 nomad-volume-plugin /opt/nomad/plugins/nomad-volume-plugin
Defensive patterns
Strategy: validation
Validate before calling
info, err := os.Stat(pluginPath)
if err != nil || info.IsDir() { return fmt.Errorf("plugin %q missing", pluginPath) }
if info.Mode()&0o111 == 0 { return fmt.Errorf("plugin %q not executable; run chmod +x", pluginPath) } Type guard
func isExecutable(info os.FileInfo) bool { return !info.IsDir() && info.Mode()&0o111 != 0 } Try / catch
if _, err := client.NewExternalSecretsPlugin(cfg); err != nil {
if errors.Is(err, commonplugins.ErrPluginNotExecutable) {
// run chmod +x on pluginPath and retry once
}
return err
} Prevention
- Install plugins with `install -m 0755` instead of plain cp
- Extract plugin archives with tools that preserve modes (tar -xzf)
- Add a startup healthcheck verifying the execute bit on every plugin in plugin_dir
- Keep plugin files on filesystems that honor Unix permissions
When it happens
Trigger: Calling NewExternalSecretsPlugin, NewHostVolumePluginExternal, or TestNewHostVolumePluginExternal when the plugin file at the configured path exists but helper.IsExecutable(f) returns false (no execute permission bits).
Common situations: Downloading or extracting a plugin archive that did not preserve the executable bit (chmod +x lost in tar/unzip), copying plugins with a non-permission-preserving tool, or provisioning the plugin_dir via a manifest/CI that resets file modes.
Related errors
- ErrVolumeNameExists
- error creating directory: %w
- error setting directory permission mode: %w
- unknown mkdir parameter: %q
- invalid value for %q: %w
AI-assisted analysis of hashicorp/nomad@482b49bf1a (2026-09-04).
Data as JSON: /api/errors/1371175975f5cbc7.
Report an issue: GitHub.