hashicorp/nomad · error

can't promote terminal deployment

Error message

can't promote terminal deployment

What it means

Sentinel ErrDeploymentTerminalNoPromote returned by the deployment endpoint when promotion is requested for an inactive (terminal) deployment. Canary promotion only applies to deployments still in progress.

Source

Thrown at nomad/structs/errors.go:81

	ErrUnknownNomadVersion        = errors.New(errUnknownNomadVersion)
	ErrNodeLacksRpc               = errors.New(errNodeLacksRpc)
	ErrMissingAllocID             = errors.New(errMissingAllocID)
	ErrIncompatibleFiltering      = errors.New(errIncompatibleFiltering)
	ErrMalformedChooseParameter   = errors.New(errMalformedChooseParameter)

	// ErrResultPaginatorCreation is returned by list RPC handlers when the
	// result paginator cannot be built, for example when the server cannot
	// evaluate a requested filter expression. api.ResultPaginatorErrorContent
	// duplicates its message so the CLI can match it without importing structs.
	// Keep the two in sync.
	ErrResultPaginatorCreation = errors.New(errResultPaginatorCreation)

	ErrUnknownNode = errors.New(ErrUnknownNodePrefix)

	ErrDeploymentTerminalNoCancel    = errors.New(errDeploymentTerminalNoCancel)
	ErrDeploymentTerminalNoFail      = errors.New(errDeploymentTerminalNoFail)
	ErrDeploymentTerminalNoPause     = errors.New(errDeploymentTerminalNoPause)
	ErrDeploymentTerminalNoPromote   = errors.New(errDeploymentTerminalNoPromote)
	ErrDeploymentTerminalNoResume    = errors.New(errDeploymentTerminalNoResume)
	ErrDeploymentTerminalNoUnblock   = errors.New(errDeploymentTerminalNoUnblock)
	ErrDeploymentTerminalNoRun       = errors.New(errDeploymentTerminalNoRun)
	ErrDeploymentTerminalNoSetHealth = errors.New(errDeploymentTerminalNoSetHealth)
	ErrDeploymentRunningNoUnblock    = errors.New(errDeploymentRunningNoUnblock)

	ErrCSIClientRPCIgnorable  = errors.New("CSI client error (ignorable)")
	ErrCSIClientRPCRetryable  = errors.New("CSI client error (retryable)")
	ErrCSIVolumeMaxClaims     = errors.New("volume max claims reached")
	ErrCSIVolumeUnschedulable = errors.New("volume is currently unschedulable")
	ErrCSIPluginInUse         = errors.New("plugin in use")
)

// IsErrNoLeader returns whether the error is due to there being no leader.
func IsErrNoLeader(err error) bool {
	return err != nil && strings.Contains(err.Error(), errNoLeader)
}

View on GitHub (pinned to 482b49bf1a)

Solutions

  1. Check the deployment is active before promoting.
  2. If the deployment already succeeded, promotion is unnecessary - treat as no-op.
  3. If it failed, re-run the job to start a new deployment instead.

Example fix

// before
client.Deployments().PromoteAll(deployID, nil)
// after
d, _ := client.Deployments().Info(deployID, nil)
if d.Status == "running" { client.Deployments().PromoteAll(deployID, nil) }
Defensive patterns

Strategy: type-guard

Validate before calling

d, err := client.Deployments().Info(deployID, nil)
if err != nil { return err }
if d.Status != "running" { return nil } // promotion not applicable

Type guard

func deploymentActive(d *api.Deployment) bool {
    return d.Status == "running" || d.Status == "pending"
}

Try / catch

err := client.Deployments().PromoteAll(deployID, nil)
if err != nil && strings.Contains(err.Error(), "terminal deployment") {
    // deployment resolved on its own; verify outcome instead of retrying
    return checkDeploymentOutcome(deployID)
}

Prevention

When it happens

Trigger: Calling Deployment.Promote (or 'nomad deployment promote') on a deployment that already succeeded, failed, or was cancelled.

Common situations: Delayed manual promotion after canaries auto-promoted or the deployment failed; CI promotion steps running after a deploy completes.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


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