hashicorp/nomad · warning

executor shutdown error: %v

Error message

executor shutdown error: %v

What it means

UniversalExecutor.shutdownProcess wraps any error from sendCtrlBreak with this message. It indicates the Windows executor failed to send the graceful Ctrl-Break shutdown event to the task process, so graceful shutdown was not performed.

Source

Thrown at drivers/shared/executor/executor_windows.go:190

	default:
		return os.NewSyscallError("WaitForSingleObject", err)
	}
}

// Send a Ctrl-Break signal for shutting down the process,
func sendCtrlBreak(pid int) error {
	err := windows.GenerateConsoleCtrlEvent(syscall.CTRL_BREAK_EVENT, uint32(pid))
	if err != nil {
		return fmt.Errorf("Error sending ctrl-break event: %v", err)
	}
	return nil
}

// Send the process a Ctrl-Break event, allowing it to shutdown by itself
// before being Terminate.
func (e *UniversalExecutor) shutdownProcess(_ os.Signal, proc *os.Process) error {
	if err := sendCtrlBreak(proc.Pid); err != nil {
		return fmt.Errorf("executor shutdown error: %v", err)
	}
	e.logger.Debug("sent Ctrl-Break to process", "pid", proc.Pid)

	return nil
}

View on GitHub (pinned to 482b49bf1a)

Solutions

  1. Inspect the wrapped cause (%v) — if it is 'process has already exited', the shutdown effectively succeeded and can be ignored
  2. Ensure the driver launches processes with CREATE_NEW_PROCESS_GROUP so Ctrl-Break is routable
  3. Rely on the subsequent TerminateProcess path to finish cleanup
  4. Update Nomad to a version with the latest Windows executor signal fixes

Example fix

// before
if err := sendCtrlBreak(proc.Pid); err != nil { return fmt.Errorf("executor shutdown error: %v", err) }
// after
if err := sendCtrlBreak(proc.Pid); err != nil { return fmt.Errorf("executor shutdown error: %v", err) }
// caller: log and fall back to ForceStop/Kill on this error
Defensive patterns

Strategy: try-catch

Validate before calling

if procAlreadyExited(pid) { return nil }

Try / catch

err := executor.Shutdown(ctx)
if err != nil && strings.Contains(err.Error(), "executor shutdown error") {
    logger.Warn("graceful shutdown failed; forcing stop", "err", err)
    executor.Kill()
}

Prevention

When it happens

Trigger: Calling UniversalExecutor.shutdownProcess (during task stop/kill) when windows.GenerateConsoleCtrlEvent fails — dead PID, missing console, or process not in a separate process group.

Common situations: Nomad stopping a Windows task whose process already exited or was started without proper console/process-group flags; shutdown timeouts cascading into kill paths.

Related errors


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