hashicorp/nomad · error
cannot destroy running task
Error message
cannot destroy running task
What it means
DestroyTask refuses to destroy a task whose handle reports IsRunning() unless force=true is passed. This is a safety guard so callers cannot accidentally destroy a live task and lose its state; the task must be stopped first, or destruction must be explicitly forced.
Source
Thrown at drivers/java/driver.go:653
if err := handle.exec.Shutdown(signal, timeout); err != nil {
if handle.pluginClient.Exited() {
return nil
}
return fmt.Errorf("executor Shutdown failed: %v", err)
}
return nil
}
func (d *Driver) DestroyTask(taskID string, force bool) error {
handle, ok := d.tasks.Get(taskID)
if !ok {
return drivers.ErrTaskNotFound
}
if handle.IsRunning() && !force {
return fmt.Errorf("cannot destroy running task")
}
if !handle.pluginClient.Exited() {
if err := handle.exec.Shutdown("", 0); err != nil {
handle.logger.Error("destroying executor failed", "error", err)
}
handle.pluginClient.Kill()
}
d.tasks.Delete(taskID)
return nil
}
func (d *Driver) InspectTask(taskID string) (*drivers.TaskStatus, error) {
handle, ok := d.tasks.Get(taskID)
if !ok {
return nil, drivers.ErrTaskNotFoundView on GitHub (pinned to 482b49bf1a)
Solutions
- Call StopTask (or DestroyTask with force=true) instead
- If you intend to discard a running task, pass force=true — the driver will then shut the executor down before cleanup
- If the task is actually dead but still reported running, check plugin client state and force-destroy to clear the stale handle
- Fix any earlier StopTask failure (e.g. hung JVM) so normal stop/destroy ordering works
Example fix
// before: destroys a running task without stopping it
err := driver.DestroyTask(taskID, false)
// after: stop first, then destroy
if err := driver.StopTask(taskID, "SIGINT", 30*time.Second); err != nil {
// log and proceed to force-destroy
}
err := driver.DestroyTask(taskID, true) Defensive patterns
Strategy: validation
Validate before calling
// check task state before destroying
if driver.IsRunning(taskID) {
if err := driver.StopTask(taskID, "SIGINT", 30*time.Second); err != nil {
// log and continue to forced destroy
}
}
err := driver.DestroyTask(taskID, true) Type guard
func canDestroy(d *drivers.Driver, taskID string, force bool) bool {
return force || !d.IsRunning(taskID)
} Try / catch
if err := driver.DestroyTask(taskID, force); err != nil {
if strings.Contains(err.Error(), "cannot destroy running task") {
_ = driver.StopTask(taskID, "SIGINT", 30*time.Second)
err = driver.DestroyTask(taskID, true)
}
return err
} Prevention
- Always stop tasks before destroying them
- Use force=true only when the intent is to discard a running task
- Handle earlier StopTask failures so tasks don't linger as running
When it happens
Trigger: Calling Driver.DestroyTask(taskID, force=false) (or equivalent GC path) while handle.IsRunning() is true — the executor is still up and the task has not been stopped — and the driver returns this plain error before any shutdown attempt.
Common situations: Operators or tooling calling destroy/GC out of order (destroy before stop), a StopTask that failed earlier leaving the task running, or automation invoking force=false destroy during cleanup.
Related errors
- cannot destroy running task
- users: release of unused uid/gid
- pre-run hook %q failed: %v
- update hook %q failed: %v
- plugin group already shutdown
AI-assisted analysis of hashicorp/nomad@482b49bf1a (2026-09-04).
Data as JSON: /api/errors/ab69b25260539afd.
Report an issue: GitHub.