hashicorp/nomad · error

need an executable to run

Error message

need an executable to run

What it means

The `subprocess` helper builds an exec.Cmd to run an executable directly (as opposed to through a shell). It refuses to build a command when the args slice is empty, since there is no binary name to execute. This guards against silently launching nothing after argument parsing.

Source

Thrown at command/var_lock.go:350

	return path, args, nil
}

// script returns a command to execute a script through a shell.
func script(ctx context.Context, args []string) (*exec.Cmd, error) {
	shell := "/bin/sh"

	if other := os.Getenv("SHELL"); other != "" {
		shell = other
	}

	return exec.CommandContext(ctx, shell, "-c", strings.Join(args, " ")), nil
}

// subprocess returns a command to execute a subprocess directly.
func subprocess(ctx context.Context, args []string) (*exec.Cmd, error) {
	if len(args) == 0 {
		return nil, fmt.Errorf("need an executable to run")
	}
	return exec.CommandContext(ctx, args[0], args[1:]...), nil
}

// ForwardSignals will fire up a goroutine to forward signals to the given
// subprocess until the context is canceled.
func (c *VarLockCommand) forwardSignals(ctx context.Context, cmd *exec.Cmd, sg chan os.Signal) {
	for {
		select {
		case sig := <-sg:
			if err := cmd.Process.Signal(sig); err != nil {
				c.varPutCommand.Ui.Error(fmt.Sprintf("failed to send signal %q: %v", sig, err))
			}

		case <-ctx.Done():
			return
		}
	}

View on GitHub (pinned to 482b49bf1a)

Solutions

  1. Supply the executable to run under the lock: `nomad var lock <path> -- <command> [args...]`.
  2. Check the script for an unset/empty variable that was meant to hold the command name.
  3. If the command is optional, guard the invocation and skip the lock subcommand when no command is given.

Example fix

// before
nomad var lock nomad/jobs/web
// after
nomad var lock nomad/jobs/web -- ./deploy.sh
Defensive patterns

Strategy: validation

Validate before calling

if [ -z "${CMD:-}" ]; then echo "usage: nomad var lock <path> -- <command> [args...]" >&2; exit 2; fi

Try / catch

err := cmd.Run()
if err != nil && strings.Contains(err.Error(), "need an executable to run") {
    log.Fatal("no command supplied after '--' to run under the lock")
}

Prevention

When it happens

Trigger: Calling code that resolves the subprocess command (e.g. `nomad var lock`'s command-execution path, or Run forwarding remaining args) passes an empty args slice to subprocess — typically when the user provided no command after flags, or flag parsing consumed everything.

Common situations: Running `nomad var lock <path>` without the trailing `-- <command>`; a script variable holding the command name expands to empty; quoting mistakes cause the shell to pass zero arguments to the lock subcommand.

Related errors


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