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

  1. Check that Launch completed successfully before sending signals
  2. Retry the signal after confirming the task is running (query task state for a real PID)
  3. Treat the error as 'task not running' — no signal delivery is possible
  4. 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

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


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