hashicorp/terraform · error
error: using a saved cloud plan when executing Terraform…
Error message
error: using a saved cloud plan when executing Terraform locally is not supported
What it means
Returned by Local.localRun when op.PlanFile.IsCloud() is true. A cloud (Terraform Cloud / HCP) plan file contains server-side references that must be redeemed by the cloud backend, not the local backend, so executing it locally is structurally unsupported rather than merely failing.
Solutions
- Apply cloud plans from within the cloud run (use the TFC/TFE UI or API), not via local `terraform apply <file>`.
- If you need a locally-applied plan, generate it locally with `terraform plan -out=tfplan` against the local (or remote-state) backend, then `terraform apply tfplan`.
- Switch the active backend to the cloud backend (`backend "cloud"`) if your intent is to apply in the cloud execution environment.
- Do not rename or copy a cloud plan file to fool IsCloud(); the format is incompatible and will fail later even if this check is bypassed.
Example fix
# before: applying a cloud-downloaded plan locally terraform apply tfplan-from-tfc # -> error: using a saved cloud plan ... not supported # after: apply it in TFC, or generate+apply locally terraform plan -out=tfplan terraform apply tfplan
Defensive patterns
Strategy: validation
Validate before calling
// Detect cloud plans up front and steer users to the right workflow.
if op.PlanFile != nil && op.PlanFile.IsCloud() {
return fmt.Errorf("a saved cloud plan cannot be applied by the local backend; apply it in TFC/TFE or generate a local plan with 'terraform plan -out'")
} Type guard
// Distinguish plan file kinds before dispatching.
func isLocalPlan(pf backendrun.PlanFile) bool {
if pf == nil { return false }
_, ok := pf.Local(); return ok
} Try / catch
lr, _, diags := b.LocalRun(ctx, op)
if diags.HasErrors() && strings.Contains(diags.Err().Error(), "saved cloud plan") {
// tell the user to switch to the cloud backend or generate a local plan
} Prevention
- Generate plans with `terraform plan -out=tfplan` against the same backend you will apply with.
- Apply cloud plans in the cloud run that produced them.
- Do not mix a TFC-downloaded plan artifact with a local apply step in CI.
When it happens
Trigger: The user runs `terraform apply <file>` (or any local operation) where <file> is a plan downloaded from a Terraform Cloud run, while the active backend is the local (or any non-cloud) backend. op.PlanFile.IsCloud() returns true and localRun short-circuits.
Common situations: Downloading a plan artifact from a TFC/TFE run and trying to apply it from a developer laptop; mixing a cloud-produced plan with a local apply workflow; CI that fetches a cloud plan but runs the apply step with the default local backend.
Related errors
- can't show a saved cloud plan unless the current root…
- PlanOutPath set without also setting PlanOutStateStore or…
- action has config values with unsupported marks
- action has ephemeral config values, which are not supported…
- at most 1 action can be invoked per operation
AI-assisted analysis of hashicorp/terraform@d32a084675 (2026-08-11).
Data as JSON: /api/errors/9a068a6cd87aac40.
Report an issue: GitHub.
Appendix: source
Thrown at internal/backend/local/backend_local.go:91
}
ret := &backendrun.LocalRun{
PolicyClient: op.PolicyClient,
}
// Initialize our context options
var coreOpts terraform.ContextOpts
if v := b.ContextOpts; v != nil {
coreOpts = *v
}
coreOpts.UIInput = op.UIIn
coreOpts.Hooks = op.Hooks
coreOpts.TracingContext = ctx
var ctxDiags tfdiags.Diagnostics
var configSnap *configload.Snapshot
if op.PlanFile.IsCloud() {
diags = diags.Append(fmt.Errorf("error: using a saved cloud plan when executing Terraform locally is not supported"))
return ret, nil, nil, diags
}
if lp, ok := op.PlanFile.Local(); ok {
var stateMeta *statemgr.SnapshotMeta
// If the statemgr implements our optional PersistentMeta interface then we'll
// additionally verify that the state snapshot in the plan file has
// consistent metadata, as an additional safety check.
if sm, ok := s.(statemgr.PersistentMeta); ok {
m := sm.StateSnapshotMeta()
stateMeta = &m
}
log.Printf("[TRACE] backend/local: populating backendrun.LocalRun from plan file")
ret, configSnap, ctxDiags = b.localRunForPlanFile(op, lp, ret, &coreOpts, stateMeta)
if ctxDiags.HasErrors() {
diags = diags.Append(ctxDiags)
return ret, nil, nil, diags
}View on GitHub (pinned to d32a084675)