hashicorp/terraform · error
resource has an unsupported mode
Error message
resource %s has an unsupported mode %s
What it means
Thrown by jsonplan.marshalResource while building the JSON plan: the switch over addr.Resource.Resource.Mode only maps addrs.ManagedResourceMode ('M') and addrs.DataResourceMode ('D'). ResourceMode also defines EphemeralResourceMode ('E'), ListResourceMode ('L'), and InvalidResourceMode (0), none of which have a JSON representation, so any of them lands in the default branch. The persistent JSON plan format is only defined for managed and data resources.
Solutions
- Upgrade Terraform to a release where the JSON plan serializer supports the resource mode you are using.
- If you are extending Terraform, add a case for the new mode (or filter it out upstream) in internal/command/jsonplan/plan.go before calling marshalResource.
- Report a bug at https://github.com/hashicorp/terraform/issues including the resource address and the mode string printed in the message.
- Regenerate the plan with the same Terraform binary that will display it to avoid cross-version plan files.
Example fix
// before
switch addr.Resource.Resource.Mode {
case addrs.ManagedResourceMode:
r.Mode = jsonstate.ManagedResourceMode
case addrs.DataResourceMode:
r.Mode = jsonstate.DataResourceMode
default:
return r, fmt.Errorf("resource %s has an unsupported mode %s", r.Address, addr.Resource.Resource.Mode.String())
}
// after (extend the serializer for the new mode or skip it)
case addrs.EphemeralResourceMode:
return r, fmt.Errorf("ephemeral resources are not represented in the JSON plan: %s", r.Address) Defensive patterns
Strategy: validation
Validate before calling
// Before calling jsonplan marshalers, filter to the modes the JSON plan can represent.
func jsonSerializableMode(m addrs.ResourceMode) bool {
switch m {
case addrs.ManagedResourceMode, addrs.DataResourceMode:
return true
}
return false
}
for _, rc := range changes {
if !jsonSerializableMode(rc.Addr.Resource.Resource.Mode) {
continue // ephemeral/list/invalid are not part of the JSON plan
}
// ... marshal rc
} Type guard
func isJSONPlanSerializableResource(a addrs.ConfigResource) bool {
switch a.Resource.Mode {
case addrs.ManagedResourceMode, addrs.DataResourceMode:
return true
}
return false
} Prevention
- Never pass ephemeral or list resources into the persistent JSON plan/state marshalers; they are intentionally unsupported.
- Keep the Terraform binary that produces a plan identical to the one that displays it.
- When extending Terraform with a new ResourceMode, update every mode switch in jsonplan and jsonstate in the same change.
When it happens
Trigger: An ephemeral or list resource (or one with a zero/Invalid mode) reaches the plan-change marshaling path; a new ResourceMode constant is added to internal/addrs without a case here; a corrupted in-memory plan object has Mode==0.
Common situations: Running an internal/dev Terraform build where ephemeral/list resources are being plumbed through plan serialization before the JSON layer is updated; a Terraform regression that routes an unsupported mode into MarshalResourceChanges; replaying a plan file produced by a mismatched Terraform binary.
Related errors
- resource has an unsupported mode
- resource has an unsupported action reason
- resource has an unsupported mode
- A managed resource address is required. Importing into a…
- error reading output values
AI-assisted analysis of hashicorp/terraform@d32a084675 (2026-08-11).
Data as JSON: /api/errors/7b070aef3da9cf98.
Report an issue: GitHub.
Appendix: source
Thrown at internal/command/jsonplan/plan.go:611
if key != nil {
if key == addrs.WildcardKey {
// The wildcard key should only be set for a deferred instance.
r.IndexUnknown = true
} else {
value := key.Value()
if r.Index, err = ctyjson.Marshal(value, value.Type()); err != nil {
return r, err
}
}
}
switch addr.Resource.Resource.Mode {
case addrs.ManagedResourceMode:
r.Mode = jsonstate.ManagedResourceMode
case addrs.DataResourceMode:
r.Mode = jsonstate.DataResourceMode
default:
return r, fmt.Errorf("resource %s has an unsupported mode %s", r.Address, addr.Resource.Resource.Mode.String())
}
r.ModuleAddress = addr.Module.String()
r.Name = addr.Resource.Resource.Name
r.Type = addr.Resource.Resource.Type
r.ProviderName = rc.ProviderAddr.Provider.String()
switch rc.ActionReason {
case plans.ResourceInstanceChangeNoReason:
r.ActionReason = "" // will be omitted in output
case plans.ResourceInstanceReplaceBecauseCannotUpdate:
r.ActionReason = ResourceInstanceReplaceBecauseCannotUpdate
case plans.ResourceInstanceReplaceBecauseTainted:
r.ActionReason = ResourceInstanceReplaceBecauseTainted
case plans.ResourceInstanceReplaceByRequest:
r.ActionReason = ResourceInstanceReplaceByRequest
case plans.ResourceInstanceReplaceByTriggers:
r.ActionReason = ResourceInstanceReplaceByTriggers
case plans.ResourceInstanceDeleteBecauseNoResourceConfig:View on GitHub (pinned to d32a084675)