{"record":{"id":"0d0ca2057f89829e","repo":"hashicorp/nomad","slug":"task-not-yet-run","errorCode":null,"errorMessage":"Task not yet run","messagePattern":"Task not yet run","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"drivers/shared/executor/executor.go","lineNumber":693,"sourceCode":"\t\te.logger.Warn(\"process did not exit after 15 seconds\")\n\t\tmerr.Errors = append(merr.Errors, fmt.Errorf(\"process did not exit after 15 seconds\"))\n\t}\n\n\tif err = merr.ErrorOrNil(); err != nil {\n\t\t// Note that proclib in the TR shutdown may also dispatch a final platform\n\t\t// cleanup technique (e.g. cgroup kill), but if we get to the point where\n\t\t// that matters the Task was doing something naughty.\n\t\te.logger.Warn(\"failed to shutdown due to some error\", \"error\", err.Error())\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\n// Signal sends the passed signal to the task\nfunc (e *UniversalExecutor) Signal(s os.Signal) error {\n\tif e.childCmd.Process == nil {\n\t\treturn fmt.Errorf(\"Task not yet run\")\n\t}\n\n\te.logger.Debug(\"sending signal to PID\", \"signal\", s, \"pid\", e.childCmd.Process.Pid)\n\terr := e.childCmd.Process.Signal(s)\n\tif err != nil {\n\t\te.logger.Error(\"sending signal failed\", \"signal\", s, \"error\", err)\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\nfunc (e *UniversalExecutor) Stats(ctx context.Context, interval time.Duration) (<-chan *cstructs.TaskResourceUsage, error) {\n\tch := make(chan *cstructs.TaskResourceUsage)\n\tgo e.handleStats(ch, ctx, interval)\n\treturn ch, nil\n}\n","sourceCodeStart":675,"sourceCodeEnd":711,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/drivers/shared/executor/executor.go#L675-L711","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\nif err := exec.Signal(syscall.SIGTERM); err != nil {\n    return err\n}\n// after\nif err := exec.Signal(syscall.SIGTERM); err != nil {\n    if strings.Contains(err.Error(), \"Task not yet run\") {\n        return nil // nothing to signal\n    }\n    return err\n}","handlingStrategy":"type-guard","validationCode":"if taskState == nil || taskState.Pid == 0 || !taskState.Running {\n    return fmt.Errorf(\"cannot signal: task is not running\")\n}","typeGuard":"func canSignal(p *os.Process) bool {\n    return p != nil && p.Signal(syscall.Signal(0)) == nil\n}","tryCatchPattern":"if err := exec.Signal(s); err != nil {\n    if strings.Contains(err.Error(), \"Task not yet run\") {\n        return fmt.Errorf(\"task %s not started; signal dropped\", taskID)\n    }\n    return err\n}","preventionTips":["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"],"tags":["signal","executor","process-lifecycle"],"backgroundTag":"process-not-found","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"}