hashicorp/nomad · error

failed to dispense plugin: %v

Error message

failed to dispense plugin: %v

What it means

To validate the config end-to-end, validatePluginConfig dispenses a throwaway instance of the plugin via l.Dispense(name, pluginType, nil, logger). Any error from Dispense — failure to launch the plugin binary, handshake failure, or the requested name/type not being registered — is wrapped as "failed to dispense plugin". The instance is killed immediately after validation.

Source

Thrown at helper/pluginutils/loader/init.go:510

	if diag.HasErrors() {
		_ = multierror.Append(&mErr, diagErrs...)
		return nil, multierror.Prefix(&mErr, "failed to parse config: ")

	}

	// Marshal the value
	cdata, err := msgpack.Marshal(val, val.Type())
	if err != nil {
		return nil, fmt.Errorf("failed to msgpack encode config: %v", err)
	}

	// Store the marshalled config
	info.msgpackConfig = cdata

	// Dispense the plugin and set its config and ensure it is error free
	instance, err := l.Dispense(id.Name, id.PluginType, nil, l.logger)
	if err != nil {
		return nil, fmt.Errorf("failed to dispense plugin: %v", err)
	}
	defer instance.Kill()

	b, ok := instance.Plugin().(base.BasePlugin)
	if !ok {
		return nil, fmt.Errorf("dispensed plugin %s doesn't meet base plugin interface", id)
	}

	c := &base.Config{
		PluginConfig: cdata,
		AgentConfig:  nil,
		ApiVersion:   info.apiVersion,
	}

	if err := b.SetConfig(c); err != nil {
		return nil, fmt.Errorf("setting config on plugin failed: %v", err)
	}

View on GitHub (pinned to 482b49bf1a)

Solutions

  1. Check the wrapped %v cause: if it's a launch/exec error, verify the plugin's exe path exists and is executable and that its checksum matches config.
  2. Run the plugin binary directly to see startup errors (missing shared libraries, wrong arch, crash on init).
  3. Ensure the plugin is still registered in the loader catalog (name + pluginType match what was registered at load time).
  4. Check host environment for process-spawn restrictions (seccomp, cgroup limits, TMPDIR writability for go-plugin sockets).
  5. Update/re-download the plugin to a build compatible with the host version.

Example fix

// before (agent config pointing at missing binary)
plugin_dir = "/opt/nomad-plugins"  # my-plugin binary absent
// after
plugin_dir = "/opt/nomad-plugins"  # with my-plugin present & chmod +x, checksum verified
Defensive patterns

Strategy: try-catch

Validate before calling

// Ensure the binary exists, is executable, and checksum matches before load
st, err := os.Stat(pluginPath)
if err != nil || st.IsDir() || st.Mode()&0111 == 0 {
    return fmt.Errorf("plugin binary %s missing or not executable", pluginPath)
}
if want, got := expectedChecksum, shaFile(pluginPath); want != got {
    return fmt.Errorf("plugin checksum mismatch: want %s got %s", want, got)
}

Try / catch

if err := loader.Load(cfg); err != nil {
    if strings.Contains(err.Error(), "failed to dispense plugin") {
        log.Printf("plugin %s could not be launched; verify binary, permissions, and handshake: %v", name, err)
        return err
    }
    return err
}

Prevention

When it happens

Trigger: validatePluginConfig calls l.Dispense(id.Name, id.PluginType, nil, l.logger) and Dispense returns an error: plugin binary can't be launched (bad path/permissions), go-plugin handshake/autoclibsys fails, or no plugin factory is registered for the (name, type) pair.

Common situations: Plugin binary deleted/moved or not executable after registration; plugin crashes during handshake (missing libs, wrong architecture, seccomp restricting forks); plugin ID mismatch between fingerprinting and dispense; resource limits preventing process spawn.

Related errors


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