hashicorp/nomad · error

unexpected executor rpc type: %T

Error message

unexpected executor rpc type: %T

What it means

Returned when Dispense("executor") succeeded but the returned raw type does not implement the local Executor interface. This indicates the plugin on the other end of the RPC is not the expected executor implementation — a programming/version mismatch rather than an environment failure, since the concrete gRPC client type should satisfy Executor.

Source

Thrown at drivers/shared/executor/utils.go:115

		return nil, nil, err
	}
	return exec, pluginClient, nil
}

func newExecutorClient(config *plugin.ClientConfig, logger hclog.Logger) (Executor, *plugin.Client, error) {
	executorClient := plugin.NewClient(config)
	rpcClient, err := executorClient.Client()
	if err != nil {
		return nil, nil, fmt.Errorf("error creating rpc client for executor plugin: %v", err)
	}

	raw, err := rpcClient.Dispense("executor")
	if err != nil {
		return nil, nil, fmt.Errorf("unable to dispense the executor plugin: %v", err)
	}
	executorPlugin, ok := raw.(Executor)
	if !ok {
		return nil, nil, fmt.Errorf("unexpected executor rpc type: %T", raw)
	}
	return executorPlugin, executorClient, nil
}

func processStateToProto(ps *ProcessState) (*proto.ProcessState, error) {
	timestamp, err := ptypes.TimestampProto(ps.Time)
	if err != nil {
		return nil, err
	}
	pb := &proto.ProcessState{
		Pid:       int32(ps.Pid),
		ExitCode:  int32(ps.ExitCode),
		Signal:    int32(ps.Signal),
		OomKilled: ps.OOMKilled,
		Time:      timestamp,
	}

	return pb, nil

View on GitHub (pinned to 482b49bf1a)

Solutions

  1. Check that ExecutorPlugin.New returns a type implementing Executor (e.g. *ExecutorClient) and is registered under "executor"
  2. Align client and server Nomad versions — reattach configs and plugin implementations must come from the same build
  3. Regenerate/rebuild proto stubs and recompile so the dispensed client satisfies the current Executor interface
  4. Audit custom plugin set overrides for accidental name collisions on "executor"

Example fix

// before: wrong implementation registered under the name
func (p *ExecutorPlugin) New(...) (interface{}, error) { return &OtherClient{}, nil }
// after
func (p *ExecutorPlugin) New(...) (interface{}, error) { return &ExecutorClient{...}, nil }
Defensive patterns

Strategy: type-guard

Validate before calling

raw, err := rpcClient.Dispense("executor")
if err != nil { return nil, nil, err }
if _, ok := raw.(Executor); !ok {
    return nil, nil, fmt.Errorf("plugin %T does not implement Executor; check build/version alignment", raw)
}

Type guard

func asExecutor(raw interface{}) (Executor, bool) {
    e, ok := raw.(Executor)
    return e, ok
}

Try / catch

executor, ok := raw.(Executor)
if !ok {
    // log the concrete type to diagnose version skew; do not proceed
    return nil, nil, fmt.Errorf("unexpected executor rpc type: %T", raw)
}

Prevention

When it happens

Trigger: The PluginSet entry named "executor" dispenses a type other than the executor's ExecutorClient (e.g. wrong plugin registered under the same name, or the Executor interface changed while the generated proto client did not), in CreateExecutor or ReattachToExecutor.

Common situations: Mismatched Nomad versions between server-dispatched driver code and client executor binaries; custom forks registering a different plugin under the "executor" name; interface drift after regenerating protobuf stubs without updating the wrapper.

Related errors


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