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
- Verify the plugin binary exists at the configured path on the Nomad client host
- Fix the plugin name/path in the task or host volume configuration
- Install the plugin binary with correct ownership (nomad user) and directory permissions
- 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
- Provision plugin binaries with config management (Ansible/Packer) so they always exist
- Use absolute paths for plugins in configuration
- Add a startup health check that stat()s each configured plugin path
- Re-verify plugin paths after OS or image upgrades
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
- plugin not executable
- ErrPluginNotExists
- intro token file is a directory
- wait config is nil or empty
- wait config is empty
AI-assisted analysis of hashicorp/nomad@482b49bf1a (2026-09-04).
Data as JSON: /api/errors/13aa7bbb72597c8c.
Report an issue: GitHub.