hashicorp/nomad · error
must call StopTask for the given task before Destroy or set
Error message
must call StopTask for the given task before Destroy or set force to true
What it means
DestroyTask refuses to remove a container that is still running unless force=true or StopTask was called first. This is a safety check so Nomad never hard-kills a running workload without a prior stop (or explicit force), since the driver tracks the task lifecycle.
Source
Thrown at drivers/docker/driver.go:1802
}
dockerClient, err := d.getDockerClient()
if err != nil {
return err
}
c, err := dockerClient.ContainerInspect(d.ctx, h.containerID, mclient.ContainerInspectOptions{})
if err != nil {
if errdefs.IsNotFound(err) {
h.logger.Info("container was removed out of band, will proceed with DestroyTask",
"error", err)
} else {
return fmt.Errorf("failed to inspect container state: %v", err)
}
} else {
if c.Container.State.Running {
if !force {
return fmt.Errorf("must call StopTask for the given task before Destroy or set force to true")
}
if _, err := dockerClient.ContainerStop(d.ctx, h.containerID, mclient.ContainerStopOptions{Timeout: new(0)}); err != nil {
h.logger.Warn("failed to stop container during destroy", "error", err)
}
}
if h.removeContainerOnExit {
if _, err := dockerClient.ContainerRemove(d.ctx, h.containerID, mclient.ContainerRemoveOptions{Force: true}); err != nil {
h.logger.Error("error removing container", "error", err)
}
} else {
h.logger.Debug("not removing container due to config")
}
}
if err := d.cleanupImage(h); err != nil {
h.logger.Error("failed to cleanup image after destroying container",
"error", err)View on GitHub (pinned to 482b49bf1a)
Solutions
- Call StopTask on the task handle before DestroyTask.
- Pass force=true to DestroyTask if you intentionally want the running container stopped and removed (the driver will ContainerStop it first).
- Fix orchestration code so the standard Stop → Destroy lifecycle is respected.
Example fix
// before h.DestroyTask(context.Background(), false) // container still running // after h.StopTask(context.Background(), time.Second*30) h.DestroyTask(context.Background(), false) // or: h.DestroyTask(ctx, true) to force-stop
Defensive patterns
Strategy: try-catch
Validate before calling
// check running state before destroy
inspected, err := client.ContainerInspect(ctx, containerID, mclient.ContainerInspectOptions{})
if err == nil && inspected.Container.State.Running {
client.ContainerStop(ctx, containerID, mclient.ContainerStopOptions{Timeout: new(uint32)})
} Try / catch
err := h.DestroyTask(ctx, false)
if err != nil && strings.Contains(err.Error(), "must call StopTask") {
h.StopTask(ctx, 30*time.Second)
err = h.DestroyTask(ctx, false)
} Prevention
- Always follow the driver lifecycle: StartTask → StopTask → DestroyTask
- Pass force=true only when intentionally tearing down running containers
- In tests/tools, assert the handle was stopped before calling destroy
When it happens
Trigger: Calling driver DestroyTask (or internal destroy APIs) directly on a handle whose container still reports State.Running=true, without having invoked StopTask and without the force flag.
Common situations: Custom tooling/plugins driving the driver API directly out of order; scripting against Nomad internals during GC tests; writing driver tests that skip the Stop step.
Related errors
- running container as ContainerAdmin is unsafe; change the co
- error decoding stats data: no reader body
- error decoding stats data: stats were nil
- does not match registry specification
- users: release of unused uid/gid
AI-assisted analysis of hashicorp/nomad@482b49bf1a (2026-09-04).
Data as JSON: /api/errors/e5da8c8e6e2a7cc6.
Report an issue: GitHub.