hashicorp/terraform · error
Unknown or unexpected cost estimate state
Error message
Unknown or unexpected cost estimate state: %s
What it means
Cost-estimate state switch hit its default: ce.Status is a value not present in the enumerated tfe.CostEstimate* constants known to this binary. Almost always a client/server version skew—the TFE server returned a newer status string the client doesn't recognize.
Solutions
- Upgrade the Terraform/OpenTofu binary to a version whose bundled tfe SDK knows the new status.
- Downgrade the TFE server side temporarily if upgrade is not possible.
- Report the unknown status value (visible in %s) to confirm it is a real enum and not corruption.
Defensive patterns
Strategy: validation
Validate before calling
func knownCostEstimateStatus(s tfe.CostEstimateStatus) bool {
switch s {
case tfe.CostEstimatePending, tfe.CostEstimateQueued, tfe.CostEstimateStarting,
tfe.CostEstimateRunning, tfe.CostEstimateFinished, tfe.CostEstimateErrored,
tfe.CostEstimateCanceled, tfe.CostEstimateSkippedDueToTargeting:
return true
}
return false
} Type guard
func isKnownCostEstimateStatus(s tfe.CostEstimateStatus) bool {
return s >= tfe.CostEstimatePending && s <= tfe.CostEstimateSkippedDueToTargeting
} Prevention
- Keep the Terraform/OpenTofu binary aligned with the TFE server version.
- Check the tfe SDK changelog when upgrading TFE.
- Log the raw status string so unknown values are diagnosable.
When it happens
Trigger: ce.Status is set by the server to a value outside {Pending, Queued, Starting, Running, Finished, Errored, Canceled, SkippedDueToTargeting, ...}. Happens when a newer TFE server introduces a new status and the client predates it.
Common situations: OpenTofu/Terraform binary built against an older tfe SDK hitting a freshly upgraded TFE; preview features adding intermediate states; rarely a corrupted/empty status field.
Related errors
- backend does not support key/value tags. Try using key-only…
- canceled.
- Unknown or unexpected policy state
- Error asking
- error creating workspace
AI-assisted analysis of hashicorp/terraform@d32a084675 (2026-08-11).
Data as JSON: /api/errors/220da315f247dfa2.
Report an issue: GitHub.
Appendix: source
Thrown at internal/cloud/backend_common.go:318
" (%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)
// Retrieve the policy check to get its current status.View on GitHub (pinned to d32a084675)