hashicorp/terraform · error
resource %s has an unsupported action reason %s
Error message
resource %s has an unsupported action reason %s
What it means
marshalResourceChange switches on rc.ActionReason, enumerating the known ResourceInstanceChangeReason values (replace/delete/read reasons). A reason value outside that set hits the default. This happens when the plan carries an action reason the renderer's switch does not cover.
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 c9def3e214)
Solutions
- Use a Terraform binary whose version matches or exceeds the one that created the plan.
- Report the unhandled action reason value (printed via %s) as a bug.
- Regenerate the plan with the rendering binary so the reason set matches.
Defensive patterns
Strategy: validation
Validate before calling
// Reject unrecognized action reasons before marshaling so the failure is
// attributed to version skew up front.
knownReasons := map[plans.ResourceInstanceChangeReason]bool{
plans.ResourceInstanceChangeNoReason: true,
plans.ResourceInstanceReplaceBecauseCannotUpdate: true,
plans.ResourceInstanceReplaceBecauseTainted: true,
plans.ResourceInstanceReplaceByRequest: true,
plans.ResourceInstanceReplaceByTriggers: true,
plans.ResourceInstanceDeleteBecauseNoResourceConfig: 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,
}
for _, rc := range plan.Changes.Resources {
if !knownReasons[rc.ActionReason] {
return fmt.Errorf("unsupported action reason %v for %s; version skew?", rc.ActionReason, rc.Addr)
}
} Prevention
- Render plans with a Terraform version equal to or newer than the one that created them.
- Regenerate plans after a Terraform upgrade instead of reusing old artifacts.
- Report any unhandled action reason value as a bug.
When it happens
Trigger: The plan was produced by a newer plans package that introduced a new ResourceInstanceChangeReason value not present in this binary's switch at plan.go:618. Reached during resource-change marshaling.
Common situations: Rendering a plan created by a newer Terraform version with an older binary that does not know the new reason; a fork adding a reason without updating jsonplan.
Related errors
- expected on 1 response value, got: %d
- failed to store state MD5: %w
- Remote workspace Terraform version %q does not match local T
- The "remote" backend does not support the %q operation.
- Unknown or unexpected cost estimate state: %s
AI-assisted analysis of hashicorp/terraform@c9def3e214 (2026-08-07).
Data as JSON: /api/errors/d5203a46111b3165.
Report an issue: GitHub.