hashicorp/nomad · error · ErrCgroupMustBeSet

error setting up exec subcommand: %w

Error message

error setting up exec subcommand: %w

What it means

setSubCmdCgroup builds the cgroup-joining cleanup hook for the exec subcommand. When the cgroup path is empty (nothing to join) it fails fast with ErrCgroupMustBeSet wrapped by this message, because without a cgroup the executor cannot contain the spawned process.

Source

Thrown at drivers/shared/executor/executor_universal_linux.go:37

	"github.com/hashicorp/nomad/plugins/drivers"
	"github.com/opencontainers/cgroups"
	"golang.org/x/sys/unix"
)

// setSubCmdCgroup sets the cgroup for non-Task child processes of the
// executor.Executor (since in cg2 it lives outside the task's cgroup)
func (e *UniversalExecutor) setSubCmdCgroup(cmd *exec.Cmd, cgroup string) (func(), error) {

	// no extra setup needed for cg v1 or when cgroups are "off"
	switch cgroupslib.GetMode() {
	case cgroupslib.OFF, cgroupslib.CG1:
		return func() {}, nil
	default:
		// continue for cg v2
	}

	if cgroup == "" {
		return nil, fmt.Errorf("error setting up exec subcommand: %w", ErrCgroupMustBeSet)
	}

	fd, cleanup, err := e.statCG(cgroup)
	if err != nil {
		return nil, err
	}

	// make sure attrs struct has been set
	if cmd.SysProcAttr == nil {
		cmd.SysProcAttr = new(syscall.SysProcAttr)
	}
	cmd.SysProcAttr.UseCgroupFD = true
	cmd.SysProcAttr.CgroupFD = fd

	return cleanup, nil
}

func (e *UniversalExecutor) ListProcesses() set.Collection[procstats.ProcessID] {

View on GitHub (pinned to 482b49bf1a)

Solutions

  1. Ensure the driver sets the cgroup path (driver config / client cgroup settings) before exec
  2. Verify client cgroup configuration (nomad client config, cgroup v1 vs v2) matches the host
  3. Check earlier cgroup creation logs for silent failures leaving path empty
  4. Upgrade/align Nomad client and driver plugin versions so cgroup setup contract is consistent

Example fix

// before (driver plugin)
execCmd := &ExecCommand{} // cgroup never set
// after
execCmd.Cgroup = cgroupsPath // computed from alloc/task ID
Defensive patterns

Strategy: validation

Validate before calling

if cgroupPath == "" {
    return fmt.Errorf("refusing to exec: cgroup path must be configured")
}

Try / catch

if err != nil && strings.Contains(err.Error(), "ErrCgroupMustBeSet") || strings.Contains(err.Error(), "setting up exec subcommand") {
    // cgroup was never set; fix driver config before retry
    return fmt.Errorf("cgroup setup missing: %w", err)
}

Prevention

When it happens

Trigger: setSubCmdCgroup is invoked on UniversalExecutor/other executors before launching a subcommand; if e.command's configured cgroup is "" after switch-handling cg versions, this error is returned.

Common situations: Driver did not configure cgroup path (e.g. TaskConfig cgroups settings dropped); running in an environment where cgroup setup was skipped or failed silently earlier; Nomad version changes around cgroup v1/v2 handling leaving path unset.

Related errors


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