hashicorp/nomad · error

Failed to stop allocation: %w

Error message

Failed to stop allocation: %w

What it means

Fires in stopAlloc during job restart: the Allocations().Stop API call to the server failed, so the allocation was not stopped and no replacement will be scheduled for it.

Source

Thrown at command/job_restart.go:955

		formatTime(time.Now()),
		shortAllocID,
		alloc.TaskGroup,
	))

	var q *api.QueryOptions

	if c.noShutdownDelay {
		q = &api.QueryOptions{
			Params: map[string]string{"no_shutdown_delay": "true"},
		}
	}

	// Stop allocation and wait for its replacement to be running or for a
	// blocked evaluation that prevents placements for this task group to
	// happen.
	resp, err := c.client.Allocations().Stop(&api.Allocation{ID: alloc.ID}, q)
	if err != nil {
		return fmt.Errorf("Failed to stop allocation: %w", err)
	}

	// Allocations for system jobs do not get replaced by the scheduler after
	// being stopped, so an eval is needed to trigger the reconciler.
	if alloc.isSystemJob() {
		opts := api.EvalOptions{
			ForceReschedule: true,
		}
		_, _, err := c.client.Jobs().EvaluateWithOpts(*alloc.Job.ID, opts, nil)
		if err != nil {
			return fmt.Errorf("Failed evaluate job: %w", err)
		}
	}

	// errCh receives an error if anything goes wrong or nil when the
	// replacement allocation is running.
	// Use a buffered channel to prevent both goroutine from blocking trying to
	// send a result back.

View on GitHub (pinned to 482b49bf1a)

Solutions

  1. Re-run nomad job restart; the command will pick up the current alloc IDs
  2. Check nomad alloc status and agent health/network connectivity
  3. Extend the query timeout / wait options used by the command
  4. Ensure the ACL token has permissions to stop allocations
Defensive patterns

Strategy: retry

Validate before calling

alloc, _, err := client.Allocations().Info(allocID, nil)
if err != nil {
    return err
}
if alloc.DesiredStatus == "stop" || isTerminal(alloc.ClientStatus) {
    return fmt.Errorf("alloc %s already stopping/terminal", allocID)
}

Type guard

func isStoppable(a *api.Allocation) bool {
    return a != nil && a.DesiredStatus != "stop" && a.ClientStatus == "running"
}

Try / catch

_, _, err := client.Allocations().Stop(&api.Allocation{ID: allocID}, q)
if err != nil {
    if errors.Is(err, context.DeadlineExceeded) || isTransientRPC(err) {
        return retryWithBackoff(func() error { _, _, err := client.Allocations().Stop(...); return err })
    }
    return err
}

Prevention

When it happens

Trigger: The Stop RPC fails — agent unreachable, alloc already garbage-collected/terminal, context/query timeout expired, or ACL token lacks permission.

Common situations: Alloc was replaced by the scheduler between listing and stopping (stale ID); node down so the client RPC fails; too-short -detach or query timeout during a slow drain; missing alloc-lifecycle ACL capability.

Related errors


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