hashicorp/nomad · error

unable to create executor config: %v

Error message

unable to create executor config: %v

What it means

CreateExecutor launches the executor as a Nomad executor plugin subprocess and must serialize the ExecutorConfig to JSON to pass it to the child. This error wraps a json.Marshal failure of *ExecutorConfig, meaning the config could not be encoded (e.g. unsupported field types such as channels, funcs, or custom marshaling errors).

Source

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

	// searching for an available port
	ExecutorDefaultMaxPort = 14512

	// ExecutorDefaultMinPort is the default min port used by the executor for
	// searching for an available port
	ExecutorDefaultMinPort = 14000
)

// CreateExecutor launches an executor plugin and returns an instance of the
// Executor interface
func CreateExecutor(
	logger hclog.Logger,
	driverConfig *base.ClientDriverConfig,
	executorConfig *ExecutorConfig,
) (Executor, *plugin.Client, error) {

	c, err := json.Marshal(executorConfig)
	if err != nil {
		return nil, nil, fmt.Errorf("unable to create executor config: %v", err)
	}
	bin, err := os.Executable()
	if err != nil {
		return nil, nil, fmt.Errorf("unable to find the nomad binary: %v", err)
	}

	p := &ExecutorPlugin{
		logger:      logger,
		fsIsolation: executorConfig.FSIsolation,
		compute:     driverConfig.Topology.Compute(),
	}

	config := &plugin.ClientConfig{
		HandshakeConfig:  base.Handshake,
		Plugins:          map[string]plugin.Plugin{"executor": p},
		Cmd:              exec.Command(bin, "executor", string(c)),
		AllowedProtocols: []plugin.Protocol{plugin.ProtocolGRPC},
		Logger:           logger.Named("executor"),

View on GitHub (pinned to 482b49bf1a)

Solutions

  1. Inspect the wrapped %v cause to find the offending field type
  2. Remove or pre-convert unserializable fields (funcs, channels) in the ExecutorConfig before calling CreateExecutor
  3. Add valid json tags and ensure all embedded types implement correct JSON encoding
  4. Test config serialization in unit tests before launching the executor plugin

Example fix

// before
cfg.FSIsolation = someFuncValue // unserializable
exec, _, _ := CreateExecutor(logger, driverCfg, cfg)
// after
cfg.IsolationKind = "chroot" // serializable string
exec, _, err := CreateExecutor(logger, driverCfg, cfg)
Defensive patterns

Strategy: validation

Validate before calling

if _, err := json.Marshal(executorConfig); err != nil { fix config fields before CreateExecutor }

Try / catch

exec, _, err := executor.CreateExecutor(logger, drvCfg, cfg)
if err != nil && strings.Contains(err.Error(), "unable to create executor config") {
    return fmt.Errorf("config not serializable: %w", err)
}

Prevention

When it happens

Trigger: Calling executor.CreateExecutor with an ExecutorConfig containing fields that json.Marshal cannot encode (function values, channels, cyclic structures, or a custom MarshalJSON that errors).

Common situations: Driver authors embedding non-serializable values into ExecutorConfig custom fields; version drift where a config struct gained an unserializable field; mismanaged struct tags on forked configs.

Understand the failure class

Background: json.Marshal / "failed to marshal" errors in Go: why "unsupported type" happens and how to fix it — this error's family across 22 libraries.

Related errors


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