{"record":{"id":"1371175975f5cbc7","repo":"hashicorp/nomad","slug":"errpluginnotexecutable","errorCode":"ErrPluginNotExecutable","errorMessage":"plugin not executable","messagePattern":"plugin not executable","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"client/hostvolumemanager/host_volumes.go","lineNumber":22,"sourceCode":"package hostvolumemanager\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"os\"\n\t\"sync\"\n\n\t\"github.com/hashicorp/go-hclog\"\n\t\"github.com/hashicorp/go-multierror\"\n\tcstructs \"github.com/hashicorp/nomad/client/structs\"\n\t\"github.com/hashicorp/nomad/helper\"\n\t\"github.com/hashicorp/nomad/nomad/structs\"\n)\n\nvar (\n\tErrPluginNotExists     = errors.New(\"no such plugin\")\n\tErrPluginNotExecutable = errors.New(\"plugin not executable\")\n\tErrVolumeNameExists    = errors.New(\"volume name already exists on this node\")\n)\n\n// HostVolumeStateManager manages the lifecycle of volumes in client state.\ntype HostVolumeStateManager interface {\n\tPutDynamicHostVolume(*cstructs.HostVolumeState) error\n\tGetDynamicHostVolumes() ([]*cstructs.HostVolumeState, error)\n\tDeleteDynamicHostVolume(string) error\n}\n\n// Config is used to configure a HostVolumeManager.\ntype Config struct {\n\t// PluginDir is where external plugins may be found.\n\tPluginDir string\n\n\t// VolumesDir is where plugins should place the directory\n\t// that will later become a volume's HostPath\n\tVolumesDir string","sourceCodeStart":4,"sourceCodeEnd":40,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/client/hostvolumemanager/host_volumes.go#L4-L40","documentation":"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.","triggerScenarios":"Calling NewExternalSecretsPlugin, NewHostVolumePluginExternal, or TestNewHostVolumePluginExternal when the plugin file at the configured path exists but helper.IsExecutable(f) returns false (no execute permission bits).","commonSituations":"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.","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"],"exampleFix":"// before\n$ cp nomad-volume-plugin /opt/nomad/plugins/  # mode 0644 -> \"plugin not executable\"\n// after\n$ install -m 0755 nomad-volume-plugin /opt/nomad/plugins/nomad-volume-plugin","handlingStrategy":"validation","validationCode":"info, err := os.Stat(pluginPath)\nif err != nil || info.IsDir() { return fmt.Errorf(\"plugin %q missing\", pluginPath) }\nif info.Mode()&0o111 == 0 { return fmt.Errorf(\"plugin %q not executable; run chmod +x\", pluginPath) }","typeGuard":"func isExecutable(info os.FileInfo) bool { return !info.IsDir() && info.Mode()&0o111 != 0 }","tryCatchPattern":"if _, err := client.NewExternalSecretsPlugin(cfg); err != nil {\n    if errors.Is(err, commonplugins.ErrPluginNotExecutable) {\n        // run chmod +x on pluginPath and retry once\n    }\n    return err\n}","preventionTips":["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"],"tags":["go","plugins","filesystem-permissions","host-volumes"],"backgroundTag":"plugin-not-executable","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"}