hashicorp/nomad · error
Task not yet run
Error message
Task not yet run
What it means
UniversalExecutor.Signal returns this when childCmd.Process is nil, meaning the task process was never started, so there is nothing to signal. Like the Shutdown variant, it guards against signaling a nonexistent process.
Source
Thrown at drivers/shared/executor/executor.go:693
e.logger.Warn("process did not exit after 15 seconds")
merr.Errors = append(merr.Errors, fmt.Errorf("process did not exit after 15 seconds"))
}
if err = merr.ErrorOrNil(); err != nil {
// Note that proclib in the TR shutdown may also dispatch a final platform
// cleanup technique (e.g. cgroup kill), but if we get to the point where
// that matters the Task was doing something naughty.
e.logger.Warn("failed to shutdown due to some error", "error", err.Error())
return err
}
return nil
}
// Signal sends the passed signal to the task
func (e *UniversalExecutor) Signal(s os.Signal) error {
if e.childCmd.Process == nil {
return fmt.Errorf("Task not yet run")
}
e.logger.Debug("sending signal to PID", "signal", s, "pid", e.childCmd.Process.Pid)
err := e.childCmd.Process.Signal(s)
if err != nil {
e.logger.Error("sending signal failed", "signal", s, "error", err)
return err
}
return nil
}
func (e *UniversalExecutor) Stats(ctx context.Context, interval time.Duration) (<-chan *cstructs.TaskResourceUsage, error) {
ch := make(chan *cstructs.TaskResourceUsage)
go e.handleStats(ch, ctx, interval)
return ch, nil
}
View on GitHub (pinned to 482b49bf1a)
Solutions
- Check that Launch completed successfully before sending signals
- Retry the signal after confirming the task is running (query task state for a real PID)
- Treat the error as 'task not running' — no signal delivery is possible
- Fix races by gating signal calls on the task's Running state
Example fix
// before
if err := exec.Signal(syscall.SIGTERM); err != nil {
return err
}
// after
if err := exec.Signal(syscall.SIGTERM); err != nil {
if strings.Contains(err.Error(), "Task not yet run") {
return nil // nothing to signal
}
return err
} Defensive patterns
Strategy: type-guard
Validate before calling
if taskState == nil || taskState.Pid == 0 || !taskState.Running {
return fmt.Errorf("cannot signal: task is not running")
} Type guard
func canSignal(p *os.Process) bool {
return p != nil && p.Signal(syscall.Signal(0)) == nil
} Try / catch
if err := exec.Signal(s); err != nil {
if strings.Contains(err.Error(), "Task not yet run") {
return fmt.Errorf("task %s not started; signal dropped", taskID)
}
return err
} Prevention
- Gate signal RPCs on task state == Running with a real PID
- Check Launch errors before any signal call
- Serialize signal calls with task startup/shutdown to remove races
When it happens
Trigger: Calling Signal(s) on an executor whose Launch failed or never ran; signaling a task concurrently with a failed start; stale task handles restored after client restart.
Common situations: Task stop/signal RPC racing task launch failure; tests signaling an un-launched executor; automation sending signals immediately after task submission before the process starts.
Related errors
- executor Shutdown failed: %v
- executor failed to shutdown error: no process found
- orphaned processes %v have not been removed from cgroups pid
- ErrCgroupMustBeSet
- user name must contain domain
AI-assisted analysis of hashicorp/nomad@482b49bf1a (2026-09-04).
Data as JSON: /api/errors/0d0ca2057f89829e.
Report an issue: GitHub.