{"record":{"id":"e47e1741c35c49f2","repo":"hashicorp/nomad","slug":"w-q-wraps-errpluginnotexecutable","errorCode":null,"errorMessage":"%w: %q (wraps ErrPluginNotExecutable)","messagePattern":"%w: %q \\(wraps ErrPluginNotExecutable\\)","errorType":"exception","errorClass":"ErrPluginNotExecutable","httpStatus":null,"severity":"error","filePath":"client/commonplugins/secrets_plugin.go","lineNumber":64,"sourceCode":"\n// NewExternalSecretsPlugin creates an instance of a secrets plugin by validating the plugin\n// binary exists and is executable, and parsing any string key/value pairs out of the config\n// which will be used as environment variables for Fetch.\nfunc NewExternalSecretsPlugin(commonPluginDir string, name string) (*externalSecretsPlugin, error) {\n\t// validate plugin\n\tif runtime.GOOS == \"windows\" {\n\t\tname += \".exe\"\n\t}\n\texecutable := filepath.Join(commonPluginDir, SecretsPluginDir, name)\n\tf, err := os.Stat(executable)\n\tif err != nil {\n\t\tif os.IsNotExist(err) {\n\t\t\treturn nil, fmt.Errorf(\"%w: %q\", ErrPluginNotExists, name)\n\t\t}\n\t\treturn nil, err\n\t}\n\tif !helper.IsExecutable(f) {\n\t\treturn nil, fmt.Errorf(\"%w: %q\", ErrPluginNotExecutable, name)\n\t}\n\n\treturn &externalSecretsPlugin{pluginPath: executable}, nil\n}\n\nfunc (e *externalSecretsPlugin) Fingerprint(ctx context.Context) (*PluginFingerprint, error) {\n\tplugCtx, cancel := context.WithTimeout(ctx, SecretsCmdTimeout)\n\tdefer cancel()\n\n\tcmd := exec.CommandContext(plugCtx, e.pluginPath, \"fingerprint\")\n\tcmd.Env = []string{\n\t\t\"CPI_OPERATION=fingerprint\",\n\t}\n\n\tstdout, stderr, err := runPlugin(cmd, SecretsKillTimeout)\n\tif err != nil {\n\t\treturn nil, err\n\t}","sourceCodeStart":46,"sourceCodeEnd":82,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/client/commonplugins/secrets_plugin.go#L46-L82","documentation":"After confirming the secrets plugin binary exists, `NewExternalSecretsPlugin` checks it is executable via helper.IsExecutable(f) and returns ErrPluginNotExecutable wrapped with the plugin name when it is not. Nomad refuses to launch plugins that lack the executable bit (or equivalent on Windows), so plugin registration fails fast with a typed, detectable error.","triggerScenarios":"Deploying the secrets plugin binary without +x permissions, e.g. extracting an archive that did not preserve modes, or copying via a tool that resets permissions; running Nomad as a user without execute permission on the file.","commonSituations":"Ansible/Docker COPY of plugin binaries losing the executable bit; binaries mounted from volumes with noexec or restrictive perms; CI artifacts uploaded without mode preservation then deployed to Nomad plugin dirs.","solutions":["chmod +x the plugin binary in the plugin directory","Ensure deployment tooling preserves file modes (e.g. `unzip`, `tar -p`, Docker COPY of a pre-built executable)","Verify the user Nomad runs as has execute permission on the file","Optionally skip optional plugins by checking errors.Is(err, commonplugins.ErrPluginNotExecutable)"],"exampleFix":"// host fix\n// before: -rw-r--r-- plugins/secrets/secrets-plugin\nchmod 0755 /opt/nomad/plugins/secrets/secrets-plugin\n// after: -rwxr-xr-x plugins/secrets/secrets-plugin","handlingStrategy":"type-guard","validationCode":"info, err := os.Stat(pluginPath)\nif err != nil {\n    log.Fatal(err)\n}\nif info.Mode()&0o111 == 0 {\n    log.Fatalf(\"plugin %s is not executable: chmod +x %s\", pluginPath, pluginPath)\n}","typeGuard":"func isPluginNotExecutable(err error) bool {\n    return errors.Is(err, commonplugins.ErrPluginNotExecutable)\n}","tryCatchPattern":"p, err := commonplugins.NewExternalSecretsPlugin(logger, name, dir)\nswitch {\ncase errors.Is(err, commonplugins.ErrPluginNotExecutable):\n    return fmt.Errorf(\"fix permissions on %s (chmod +x)\", name)\ncase err != nil:\n    return err\n}","preventionTips":["chmod 0755 plugin binaries after deployment","Use deployment tooling that preserves file modes (tar -p, unzip -X, correct Docker COPY)","Verify plugin permissions in post-deploy health checks","Ensure the Nomad service user can execute the plugin directory tree"],"tags":["nomad","plugin","secrets","permissions"],"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"}