hashicorp/terraform · warning
canceled.
Error message
%s canceled.
What it means
During the cost-estimation polling loop, the run's CostEstimate entered tfe.CostEstimateCanceled—someone or something (user, admin, or an auto-cancel policy) aborted the cost estimate. The backend converts this into a fatal error for the run rather than continuing silently.
Solutions
- Re-trigger the run and avoid canceling it from the UI mid-flight.
- Disable cost estimation for the workspace if it consistently times out.
- Coordinate CI and operators so only one source controls a run's lifecycle.
Defensive patterns
Strategy: try-catch
Try / catch
if err := b.checkCostEstimation(ctx, op, r); err != nil {
if strings.Contains(err.Error(), "canceled") {
// surface to user / re-trigger the run
return retryRun(r.ID)
}
return err
} Prevention
- Coordinate so only one actor (CI or operator) controls a run's lifecycle.
- Disable cost estimation on workspaces where it consistently gets canceled.
- Watch the run in the UI when long cost estimates are expected.
When it happens
Trigger: ce.Status transitions to tfe.CostEstimateCanceled while the backend polls the cost estimate. Triggered by a user clicking Cancel in the UI, a run being discarded, or an org-level policy auto-canceling runs.
Common situations: Operator manually cancels a long cost estimate; another teammate discards the run from the UI while CI is waiting; CI timeout in the upstream orchestrator sends a cancel request to TFE.
Related errors
- Unknown or unexpected cost estimate state
- backend does not support key/value tags. Try using key-only…
- Error asking
- error creating workspace
- error finding remote workspace
AI-assisted analysis of hashicorp/terraform@d32a084675 (2026-08-11).
Data as JSON: /api/errors/e6f2574cca20c432.
Report an issue: GitHub.
Appendix: source
Thrown at internal/cloud/backend_common.go:316
if i > 0 {
elapsed = fmt.Sprintf(
" (%s elapsed)", current.Sub(started).Truncate(30*time.Second))
}
b.CLI.Output(b.Colorize().Color("[bold]" + msgPrefix + ":\n"))
b.CLI.Output(b.Colorize().Color("Waiting for cost estimate to complete..." + elapsed + "\n"))
}
continue
case tfe.CostEstimateSkippedDueToTargeting:
b.CLI.Output(b.Colorize().Color("[bold]" + msgPrefix + ":\n"))
b.CLI.Output("Not available for this plan, because it was created with the -target option.")
b.CLI.Output("\n------------------------------------------------------------------------")
return nil
case tfe.CostEstimateErrored:
b.CLI.Output(msgPrefix + " errored.\n")
b.CLI.Output("\n------------------------------------------------------------------------")
return nil
case tfe.CostEstimateCanceled:
return fmt.Errorf("%s canceled.", msgPrefix)
default:
return fmt.Errorf("Unknown or unexpected cost estimate state: %s", ce.Status)
}
}
}
func (b *Cloud) checkPolicy(stopCtx, cancelCtx context.Context, op *backendrun.Operation, r *tfe.Run) error {
if b.CLI != nil {
b.CLI.Output("\n------------------------------------------------------------------------\n")
}
for i, pc := range r.PolicyChecks {
// Read the policy check logs. This is a blocking call that will only
// return once the policy check is complete.
logs, err := b.client.PolicyChecks.Logs(stopCtx, pc.ID)
if err != nil {
return b.generalError("Failed to retrieve policy check logs", err)
}
reader := bufio.NewReaderSize(logs, 64*1024)View on GitHub (pinned to d32a084675)