hashicorp/nomad · error · ErrPluginNotExists

plugin not found

Error message

plugin not found

What it means

ErrPluginNotExists is a sentinel error wrapped when a Nomad external/common plugin binary cannot be found on disk. It is returned by constructors for external secrets and host volume plugins after the underlying file open fails with a not-exist error. The wrapper adds the plugin name/path so developers can tell which plugin was missing.

Source

Thrown at client/commonplugins/commonplugins.go:18

// 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) {

View on GitHub (pinned to 482b49bf1a)

Solutions

  1. Verify the plugin binary exists at the configured path on the Nomad client host
  2. Fix the plugin name/path in the task or host volume configuration
  3. Install the plugin binary with correct ownership (nomad user) and directory permissions
  4. Check client logs for the exact wrapped path to confirm which file is missing

Example fix

// before
plugin = "cni-secrets" // binary not installed
// after
# ensure /opt/nomad/plugins/cni-secrets exists and config uses full path
plugin = "/opt/nomad/plugins/cni-secrets"
Defensive patterns

Strategy: validation

Validate before calling

// before configuring the plugin, verify it exists
p := "/opt/nomad/plugins/cni-secrets"
if _, err := os.Stat(p); errors.Is(err, os.ErrNotExist) {
    return fmt.Errorf("plugin %q must be installed first", p)
}

Type guard

func pluginExists(path string) bool {
    _, err := os.Stat(path)
    return err == nil
}

Try / catch

plugin, err := NewExternalSecretsPlugin(cfg)
if err != nil {
    if errors.Is(err, ErrPluginNotExists) {
        // install or fix plugin path, then retry
        return installPlugin(name)
    }
    return err
}

Prevention

When it happens

Trigger: NewExternalSecretsPlugin, NewHostVolumePluginExternal, or TestNewHostVolumePluginExternal is called with a plugin name whose binary does not exist at the expected path (os.Open/ReadDir fails with os.IsNotExist, or os.OpenRoot fails on the plugin dir).

Common situations: Typo in plugin name or path in task config; plugin binary not installed/chowned correctly on the client; plugin directory missing after OS image rebuild; case-sensitive path mismatch on Linux.

Understand the failure class

Background: "File not found" and ENOENT errors: why libraries can't find a file that should exist — this error's family across 50 libraries.

Related errors


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