hashicorp/nomad · error · ErrPluginNotExecutable
plugin not executable
Error message
plugin not executable
What it means
ErrPluginNotExecutable is a sentinel error returned when a Nomad external/common plugin binary exists but is not executable (helper.IsExecutable check fails). It is wrapped with the plugin name by the same constructors as ErrPluginNotExists.
Source
Thrown at client/commonplugins/commonplugins.go:19
// Copyright IBM Corp. 2015, 2026
// SPDX-License-Identifier: BUSL-1.1
package commonplugins
import (
"bytes"
"context"
"errors"
"os/exec"
"syscall"
"time"
"github.com/hashicorp/go-version"
)
var (
ErrPluginNotExists error = errors.New("plugin not found")
ErrPluginNotExecutable error = errors.New("plugin not executable")
)
type CommonPlugin interface {
Fingerprint(ctx context.Context) (*PluginFingerprint, error)
}
// CommonPlugins are expected to respond to 'fingerprint' calls with json that
// unmarshals to this struct.
type PluginFingerprint struct {
Version *version.Version `json:"version"`
Type *string `json:"type"`
}
// runPlugin is a helper for executing the provided Cmd and capturing stdout/stderr.
// This helper implements both the soft and hard timeouts defined by the common
// plugins interface.
func runPlugin(cmd *exec.Cmd, killTimeout time.Duration) (stdout, stderr []byte, err error) {
var errBuf bytes.BufferView on GitHub (pinned to 482b49bf1a)
Solutions
- chmod +x the plugin binary on the client host
- Re-install the plugin preserving executable permissions (e.g. tar --preserve-permissions, install -m 0755)
- Confirm the file is a real executable (file <path>) and not a truncated/corrupt download
- Ensure the nomad user can traverse the plugin directory and execute the file
Example fix
// before (shell provisioning) wget -O /opt/nomad/plugins/csi-plugin https://example.com/csi-plugin // after wget -O /opt/nomad/plugins/csi-plugin https://example.com/csi-plugin && chmod 0755 /opt/nomad/plugins/csi-plugin
Defensive patterns
Strategy: validation
Validate before calling
// before configuring the plugin, verify it is executable
info, err := os.Stat(p)
if err != nil {
return err
}
if info.Mode()&0111 == 0 {
return fmt.Errorf("plugin %q is not executable; run chmod +x", p)
} Type guard
func pluginExecutable(path string) bool {
info, err := os.Stat(path)
return err == nil && info.Mode()&0111 != 0
} Try / catch
plugin, err := NewHostVolumePluginExternal(cfg)
if err != nil {
if errors.Is(err, ErrPluginNotExecutable) {
if execErr := os.Chmod(pluginPath, 0o755); execErr != nil {
return execErr
}
return retryNewPlugin(cfg)
}
return err
} Prevention
- Always chmod 0755 plugin binaries during provisioning
- Extract archives with permission preservation (tar -p / umask 022)
- Verify executability in CI/CD images that ship plugins
- Ensure the nomad service user can execute the binary (ownership + dir traversal)
When it happens
Trigger: NewExternalSecretsPlugin, NewHostVolumePluginExternal, or TestNewHostVolumePluginExternal locate the plugin file but helper.IsExecutable(f) returns false — i.e. no execute bit set or file is not a regular executable file.
Common situations: Plugin binary downloaded/tar-extracted without preserving permissions; chmod +x forgotten in provisioning scripts; umask stripped execute bit; plugin replaced by a data file or script lacking +x; non-root nomad user cannot execute due to permissions on parent dirs.
Understand the failure class
Background: Permission denied / not authorized / 403 Forbidden: access-control rejections when the caller lacks the required role, grant, or ownership — this error's family across 18 libraries.
Related errors
- plugin not found
- ErrPluginNotExists
- Chmod(%v) failed: %w
- Couldn't change owner/group of %v to (uid: %v, gid: %v): %w
- unable to remove existing unix socket: %w
AI-assisted analysis of hashicorp/nomad@482b49bf1a (2026-09-04).
Data as JSON: /api/errors/567aca77a466549f.
Report an issue: GitHub.