hashicorp/terraform · error
remote backend doesn't support %s
Error message
remote backend doesn't support %s
What it means
Thrown by the remote (Terraform Cloud/Enterprise) backend when the plan operation carries a plans.PlanMode value that the backend's switch statement in backend_plan.go:302-317 does not recognize. Only NormalMode, RefreshOnlyMode, and DestroyMode are mapped to RunCreateOptions fields; any other mode reaches the default branch and is treated as a programming/contract defect (the code comment at line 310 explicitly says it should be updated for each new plan mode). It signals that a new plan mode was added to Terraform core without a corresponding case in this remote backend.
Source
Thrown at internal/backend/remote/backend_plan.go:315
ConfigurationVersion: cv,
Refresh: tfe.Bool(op.PlanRefresh),
Workspace: w,
}
switch op.PlanMode {
case plans.NormalMode:
// okay, but we don't need to do anything special for this
case plans.RefreshOnlyMode:
runOptions.RefreshOnly = tfe.Bool(true)
case plans.DestroyMode:
runOptions.IsDestroy = tfe.Bool(true)
default:
// Shouldn't get here because we should update this for each new
// plan mode we add, mapping it to the corresponding RunCreateOptions
// field.
return nil, generalError(
"Invalid plan mode",
fmt.Errorf("remote backend doesn't support %s", op.PlanMode),
)
}
if len(op.Targets) != 0 {
runOptions.TargetAddrs = make([]string, 0, len(op.Targets))
for _, addr := range op.Targets {
runOptions.TargetAddrs = append(runOptions.TargetAddrs, addr.String())
}
}
if len(op.ForceReplace) != 0 {
runOptions.ReplaceAddrs = make([]string, 0, len(op.ForceReplace))
for _, addr := range op.ForceReplace {
runOptions.ReplaceAddrs = append(runOptions.ReplaceAddrs, addr.String())
}
}
r, err := b.client.Runs.Create(stopCtx, runOptions)View on GitHub (pinned to c9def3e214)
Solutions
- Check the value of op.PlanMode at the call site and only forward NormalMode/RefreshOnlyMode/DestroyMode to the remote backend plan operation.
- Upgrade the remote backend package (this file) to the version that adds a switch case for the new plan mode, mapping it to the matching tfe.RunCreateOptions field.
- If you maintain a fork, add the missing case in backend_plan.go:302 and open/refresh upstream support for that plan mode.
- Downgrade the caller to a Terraform core version whose plan modes are all covered by the remote backend.
Example fix
// before
runOptions := buildRunOptions(op) // op.PlanMode == plans.SomeNewMode -> default branch errors
// after
switch op.PlanMode {
case plans.NormalMode:
case plans.RefreshOnlyMode:
runOptions.RefreshOnly = tfe.Bool(true)
case plans.DestroyMode:
runOptions.IsDestroy = tfe.Bool(true)
case plans.SomeNewMode:
runOptions.SomeNewField = tfe.Bool(true) // add the case for the new mode
default:
return nil, generalError("Invalid plan mode", fmt.Errorf("remote backend doesn't support %s", op.PlanMode))
} Defensive patterns
Strategy: validation
Validate before calling
// Before invoking the remote backend plan operation, reject unsupported modes.
func supportedPlanMode(m plans.Mode) error {
switch m {
case plans.NormalMode, plans.RefreshOnlyMode, plans.DestroyMode:
return nil
}
return fmt.Errorf("remote backend does not support plan mode %s; use a supported mode", m)
}
if err := supportedPlanMode(op.PlanMode); err != nil { return err } Prevention
- When adding a new plans.Mode constant, add the matching switch case in backend_plan.go:302 in the same change.
- Add a unit test that enumerates all plans.Mode values and asserts each is handled by the switch.
- Keep the Terraform CLI version aligned with the remote backend package version.
When it happens
Trigger: Calling the remote backend Operation with an op.PlanMode outside {plans.NormalMode, plans.RefreshOnlyMode, plans.DestroyMode}. Concretely this happens when Terraform core introduces a new plans.Mode constant and a CLI/wrapper passes it through to the remote backend's plan path before backend_plan.go is updated.
Common situations: A new Terraform release adds a plan mode (e.g. a future mode beyond refresh-only/destroy) but the user's remote backend code is from an older revision; or a custom fork/patch sets op.PlanMode to an experimental value. Mismatched Terraform CLI and backend library versions.
Related errors
- Error retrieving state: %v
- Error downloading state: %v
- Task stage '%s' has invalid status: %s
- %s doesn't support %s
- saved backend configuration is invalid: %w
AI-assisted analysis of hashicorp/terraform@c9def3e214 (2026-08-07).
Data as JSON: /api/errors/e4292152b8a437ed.
Report an issue: GitHub.