{"record":{"id":"408ad8ab34712b9d","repo":"hashicorp/nomad","slug":"error-setting-up-exec-subcommand-w","errorCode":null,"errorMessage":"error setting up exec subcommand: %w","messagePattern":"error setting up exec subcommand: %w","errorType":"exception","errorClass":"ErrCgroupMustBeSet","httpStatus":null,"severity":"error","filePath":"drivers/shared/executor/executor_universal_linux.go","lineNumber":37,"sourceCode":"\t\"github.com/hashicorp/nomad/plugins/drivers\"\n\t\"github.com/opencontainers/cgroups\"\n\t\"golang.org/x/sys/unix\"\n)\n\n// setSubCmdCgroup sets the cgroup for non-Task child processes of the\n// executor.Executor (since in cg2 it lives outside the task's cgroup)\nfunc (e *UniversalExecutor) setSubCmdCgroup(cmd *exec.Cmd, cgroup string) (func(), error) {\n\n\t// no extra setup needed for cg v1 or when cgroups are \"off\"\n\tswitch cgroupslib.GetMode() {\n\tcase cgroupslib.OFF, cgroupslib.CG1:\n\t\treturn func() {}, nil\n\tdefault:\n\t\t// continue for cg v2\n\t}\n\n\tif cgroup == \"\" {\n\t\treturn nil, fmt.Errorf(\"error setting up exec subcommand: %w\", ErrCgroupMustBeSet)\n\t}\n\n\tfd, cleanup, err := e.statCG(cgroup)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// make sure attrs struct has been set\n\tif cmd.SysProcAttr == nil {\n\t\tcmd.SysProcAttr = new(syscall.SysProcAttr)\n\t}\n\tcmd.SysProcAttr.UseCgroupFD = true\n\tcmd.SysProcAttr.CgroupFD = fd\n\n\treturn cleanup, nil\n}\n\nfunc (e *UniversalExecutor) ListProcesses() set.Collection[procstats.ProcessID] {","sourceCodeStart":19,"sourceCodeEnd":55,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/drivers/shared/executor/executor_universal_linux.go#L19-L55","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Ensure the driver sets the cgroup path (driver config / client cgroup settings) before exec","Verify client cgroup configuration (nomad client config, cgroup v1 vs v2) matches the host","Check earlier cgroup creation logs for silent failures leaving path empty","Upgrade/align Nomad client and driver plugin versions so cgroup setup contract is consistent"],"exampleFix":"// before (driver plugin)\nexecCmd := &ExecCommand{} // cgroup never set\n// after\nexecCmd.Cgroup = cgroupsPath // computed from alloc/task ID","handlingStrategy":"validation","validationCode":"if cgroupPath == \"\" {\n    return fmt.Errorf(\"refusing to exec: cgroup path must be configured\")\n}","typeGuard":null,"tryCatchPattern":"if err != nil && strings.Contains(err.Error(), \"ErrCgroupMustBeSet\") || strings.Contains(err.Error(), \"setting up exec subcommand\") {\n    // cgroup was never set; fix driver config before retry\n    return fmt.Errorf(\"cgroup setup missing: %w\", err)\n}","preventionTips":["Ensure drivers always populate the cgroup path in ExecCommand","Align client cgroup v1/v2 configuration with driver expectations","Log cgroup path at task launch to catch empty values early"],"tags":["cgroups","executor","configuration"],"backgroundTag":"cgroup-not-set","analyzedSha":"482b49bf1aec006f089bcfc7e632d8f6ac303e5e","analyzedAt":"2026-09-04T07:54:14.808Z","contentChangedAt":"2026-09-04T07:54:14.808Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}