hashicorp/terraform · error
resource has an unsupported action reason
Error message
resource %s has an unsupported action reason %s
What it means
Thrown by jsonplan.marshalResource when mapping the internal plans.ResourceInstanceChangeReason enum to its JSON string form. The switch lists a fixed set of reasons (replace-because-cannot-update, tainted, delete-because-*, read-because-*). A planned change whose ActionReason is not one of those mapped constants falls through to default. This usually means the plans package grew a new reason constant that the JSON layer was not updated to recognize.
Solutions
- Use the same Terraform version to produce and consume the plan.
- Upgrade Terraform so the jsonplan switch covers all current ActionReason values.
- If extending Terraform, add the missing case mapping in internal/command/jsonplan/plan.go near line 648.
- Report the unmapped reason string from the error message upstream.
Example fix
// before
default:
return r, fmt.Errorf("resource %s has an unsupported action reason %s", r.Address, rc.ActionReason)
// after (map the new constant to its JSON string)
case plans.ResourceInstanceReplaceBecauseGreaterThan:
r.ActionReason = ResourceInstanceReplaceBecauseGreaterThan Defensive patterns
Strategy: validation
Validate before calling
// Guard before marshaling: skip or map only known action reasons.
var knownReasons = map[plans.ResourceInstanceChangeReason]bool{
plans.ResourceInstanceChangeNoReason: true,
plans.ResourceInstanceReplaceBecauseCannotUpdate: true,
plans.ResourceInstanceReplaceBecauseTainted: true,
plans.ResourceInstanceReplaceByRequest: true,
plans.ResourceInstanceDeleteBecauseNoResource: true,
plans.ResourceInstanceDeleteBecauseWrongRepetition: true,
plans.ResourceInstanceDeleteBecauseCountIndex: true,
plans.ResourceInstanceDeleteBecauseEachKey: true,
plans.ResourceInstanceDeleteBecauseNoModule: true,
plans.ResourceInstanceDeleteBecauseNoMoveTarget: true,
plans.ResourceInstanceReadBecauseConfigUnknown: true,
plans.ResourceInstanceReadBecauseDependencyPending: true,
plans.ResourceInstanceReadBecauseCheckNested: true,
}
if !knownReasons[rc.ActionReason] {
return fmt.Errorf("skipping change with unmapped action reason %d", rc.ActionReason)
} Prevention
- Keep plans and jsonplan packages in sync when adding a ResourceInstanceChangeReason constant.
- Consume a plan with the same Terraform version that produced it.
- Treat a new reason string as a signal to update the JSON mapping, not an ignorable default.
When it happens
Trigger: A new plans.ResourceInstanceChange*Reason constant is added without a matching case; a provider/SDK path sets an ActionReason value outside the documented set; an internal regression assigns a zero/garbage reason.
Common situations: Cross-binary plan consumption (plan produced by a newer Terraform, shown by an older one); running an unreleased/dev build whose plans and jsonplan packages are out of sync.
Related errors
- resource has an unsupported mode
- resource has an unsupported mode
- resource has an unsupported mode
- error reading output values
- error reading state
AI-assisted analysis of hashicorp/terraform@d32a084675 (2026-08-11).
Data as JSON: /api/errors/d5203a46111b3165.
Report an issue: GitHub.
Appendix: source
Thrown at internal/command/jsonplan/plan.go:648
r.ActionReason = ResourceInstanceDeleteBecauseNoResourceConfig
case plans.ResourceInstanceDeleteBecauseWrongRepetition:
r.ActionReason = ResourceInstanceDeleteBecauseWrongRepetition
case plans.ResourceInstanceDeleteBecauseCountIndex:
r.ActionReason = ResourceInstanceDeleteBecauseCountIndex
case plans.ResourceInstanceDeleteBecauseEachKey:
r.ActionReason = ResourceInstanceDeleteBecauseEachKey
case plans.ResourceInstanceDeleteBecauseNoModule:
r.ActionReason = ResourceInstanceDeleteBecauseNoModule
case plans.ResourceInstanceDeleteBecauseNoMoveTarget:
r.ActionReason = ResourceInstanceDeleteBecauseNoMoveTarget
case plans.ResourceInstanceReadBecauseConfigUnknown:
r.ActionReason = ResourceInstanceReadBecauseConfigUnknown
case plans.ResourceInstanceReadBecauseDependencyPending:
r.ActionReason = ResourceInstanceReadBecauseDependencyPending
case plans.ResourceInstanceReadBecauseCheckNested:
r.ActionReason = ResourceInstanceReadBecauseCheckNested
default:
return r, fmt.Errorf("resource %s has an unsupported action reason %s", r.Address, rc.ActionReason)
}
return r, nil
}
// MarshalDeferredResourceChanges converts the provided internal representation
// of DeferredResourceInstanceChangeSrc objects into the public structured JSON
// changes.
// This is public to make testing easier.
func MarshalDeferredResourceChanges(resources []*plans.DeferredResourceInstanceChangeSrc, schemas *terraform.Schemas) ([]DeferredResourceChange, error) {
var ret []DeferredResourceChange
var sortedResources []*plans.DeferredResourceInstanceChangeSrc
sortedResources = append(sortedResources, resources...)
sort.Slice(sortedResources, func(i, j int) bool {
if !sortedResources[i].ChangeSrc.Addr.Equal(sortedResources[j].ChangeSrc.Addr) {
return sortedResources[i].ChangeSrc.Addr.Less(sortedResources[j].ChangeSrc.Addr)
}View on GitHub (pinned to d32a084675)