hashicorp/nomad · warning
Error sending ctrl-break event: %v
Error message
Error sending ctrl-break event: %v
What it means
sendCtrlBreak wraps the failure of windows.GenerateConsoleCtrlEvent, which delivers CTRL_BREAK_EVENT to a task process so it can shut down gracefully. This error means the console control event could not be delivered to the given PID.
Source
Thrown at drivers/shared/executor/executor_windows.go:181
result, err := syscall.WaitForSingleObject(syscall.Handle(handle), 0)
switch result {
case syscall.WAIT_OBJECT_0:
return nil
case syscall.WAIT_TIMEOUT:
// Process still running. Just kill it.
return proc.Kill()
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
- Check whether the target process is still alive before/while signaling (accept the error if the process already exited)
- Ensure the executor spawned the process with an attached console and new process group so CTRL_BREAK_EVENT is deliverable
- Fall back to process termination (Kill) which is the documented next step in shutdownProcess handling
- Retry the signal once; transient failures can occur during process teardown
Example fix
// before
if err := sendCtrlBreak(proc.Pid); err != nil { return err }
// after
if err := sendCtrlBreak(proc.Pid); err != nil {
logger.Warn("ctrl-break failed, killing", "pid", proc.Pid, "err", err)
return proc.Kill()
} Defensive patterns
Strategy: try-catch
Validate before calling
alive, err := isProcessAlive(pid); if !alive { skip ctrl-break } Try / catch
err := executor.Signal(syscall.SIGBREAK)
if err != nil && strings.Contains(err.Error(), "ctrl-break") {
// fall back to force kill / ignore if process already exited
} Prevention
- Verify the task process is alive before signaling
- Spawn task processes with CREATE_NEW_PROCESS_GROUP
- Treat shutdown-signal errors as best-effort with a terminate fallback
When it happens
Trigger: Calling sendCtrlBreak with a PID whose process has exited, has no attached console, or was not started with CREATE_NEW_PROCESS_GROUP / shares no console with the caller.
Common situations: Shutting down an already-dead task during Nomad kill/stop flows; processes started detached from the console; races where the task exits between signal decision and delivery.
Related errors
- executor shutdown error: %v
- eventlog.level must be one of INFO, WARN, or ERROR
- running container as ContainerAdmin is unsafe; change the co
- QEMU graceful shutdown is unsupported on the Windows platfor
- QEMU Guest Agent socket is unsupported on the Windows platfo
AI-assisted analysis of hashicorp/nomad@482b49bf1a (2026-09-04).
Data as JSON: /api/errors/218e22067d401f70.
Report an issue: GitHub.