hashicorp/nomad · error

specified binary is invalid: %v

Error message

specified binary is invalid: %v

What it means

If os.Stat on the binary fails with an error other than NotExist, makeExecutable returns 'specified binary is invalid: %v' wrapping the underlying error (permission denied on a parent directory, path is a directory, I/O error, etc.). Raised from Launch, so the task cannot start until the path resolves to a stat-able regular file.

Source

Thrown at drivers/shared/executor/executor.go:783

	if host, err := exec.LookPath(bin); err == nil {
		return host, nil
	}

	return "", fmt.Errorf("binary %q could not be found", bin)
}

// makeExecutable makes the given file executable for root,group,others.
func makeExecutable(binPath string) error {
	if runtime.GOOS == "windows" {
		return nil
	}

	fi, err := os.Stat(binPath)
	if err != nil {
		if os.IsNotExist(err) {
			return fmt.Errorf("binary %q does not exist", binPath)
		}
		return fmt.Errorf("specified binary is invalid: %v", err)
	}

	// If it is not executable, make it so.
	perm := fi.Mode().Perm()
	req := os.FileMode(0555)
	if perm&req != req {
		if err := os.Chmod(binPath, perm|req); err != nil {
			return fmt.Errorf("error making %q executable: %s", binPath, err)
		}
	}
	return nil
}

// SupportedCaps returns a list of all supported capabilities in kernel.
func SupportedCaps(allowNetRaw bool) []string {
	var allCaps []string
	list, _ := capability.ListSupported()
	for _, cap := range list {

View on GitHub (pinned to 482b49bf1a)

Solutions

  1. Read the wrapped inner error to identify the stat failure (EACCES, EISDIR, etc.)
  2. Ensure the path points to a regular executable file, not a directory
  3. Fix permissions on the binary and each parent directory so the Nomad client user can traverse them
  4. Check mounts/links on the client if stat reports I/O or loop errors

Example fix

// before
config { command = "/opt/app/bin" } // a directory
// after
config { command = "/opt/app/bin/server" }
Defensive patterns

Strategy: validation

Validate before calling

fi, err := os.Stat(binPath)
if err != nil {
    return fmt.Errorf("cannot stat %s: %w", binPath, err)
}
if fi.IsDir() {
    return fmt.Errorf("%s is a directory, not an executable", binPath)
}

Type guard

func isRegularExecutable(path string) bool {
    fi, err := os.Stat(path)
    return err == nil && fi.Mode().IsRegular() && fi.Mode().Perm()&0111 != 0
}

Try / catch

if err := client.Launch(...); err != nil {
    if strings.Contains(err.Error(), "specified binary is invalid") {
        return fmt.Errorf("check path/permissions on client: %w", err)
    }
    return err
}

Prevention

When it happens

Trigger: Launching a task whose command path is a directory instead of a file; a parent directory lacks execute/search permission for the Nomad user; symlink loops or filesystem errors during stat.

Common situations: Config pointing at a directory (e.g. /usr/bin instead of /usr/bin/tool); restrictive permissions after deploying as another user; broken mount or network filesystem on the client.

Related errors


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