hashicorp/terraform · error
canceled.
Error message
%s canceled.
What it means
Returned by the cost-estimation watcher when the run's cost estimate transitions to tfe.CostEstimateCanceled. The %s is msgPrefix (the 'Cost Estimation' header). It signals an externally-initiated cancellation of the cost-estimate phase of a remote run.
Solutions
- Confirm the cancellation was intentional; if accidental, start a new run.
- If cancellations are recurring, review who/what has cancel permissions and any automation that may abort runs.
- Re-run the plan/apply once the underlying cause is resolved.
Defensive patterns
Strategy: try-catch
Try / catch
// Treat a canceled cost estimate as a terminal-but-recoverable run outcome.
if errors.Is(err, errCostEstimateCanceled) {
// prompt user / automation to start a new run; do not auto-retry blindly Prevention
- Restrict who/what can cancel runs to avoid accidental aborts.
- Surface cancellation events to automation so a new run can be queued deterministically.
- Do not retry a canceled run without user/automation confirmation - investigate the cancel source first.
When it happens
Trigger: During checkCostEstimation the polled ce.Status equals tfe.CostEstimateCanceled. Triggered when a user clicks 'Cancel Run' in the TFC/TFE UI mid-cost-estimate, or the run is canceled via API while cost estimation is in progress.
Common situations: Manual run cancellation in the UI; automated cancellation by a policy/automation; cost-estimation service issue causing TFE to mark the phase canceled; concurrent cancel during a long plan.
Related errors
- Unknown or unexpected cost estimate state
- Error asking
- Error creating workspace
- error finding remote workspace
- error loading state
AI-assisted analysis of hashicorp/terraform@d32a084675 (2026-08-11).
Data as JSON: /api/errors/cc049afadde28bd0.
Report an issue: GitHub.
Appendix: source
Thrown at internal/backend/remote/backend_common.go:366
if i > 0 {
elapsed = fmt.Sprintf(
" (%s elapsed)", current.Sub(started).Truncate(30*time.Second))
}
b.CLI.Output(b.Colorize().Color(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(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 *Remote) 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 generalError("Failed to retrieve policy check logs", err)
}
reader := bufio.NewReaderSize(logs, 64*1024)View on GitHub (pinned to d32a084675)