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 string

View on GitHub (pinned to 482b49bf1a)

Solutions

  1. chmod +x the plugin binary inside the configured plugin_dir
  2. Re-download/re-extract the plugin preserving permissions (tar -xzf keeps modes)
  3. Verify the configured path points at the binary itself, not a data or README file
  4. 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

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


AI-assisted analysis of hashicorp/nomad@482b49bf1a (2026-09-04). Data as JSON: /api/errors/1371175975f5cbc7. Report an issue: GitHub.