hashicorp/terraform · critical
unrecognized action slice:
Error message
unrecognized action slice:
What it means
A panic in `UnmarshalActions` (internal/command/jsonplan/plan.go:1030) when a plan's `actions` slice for a resource change does not match any known single action (create/delete/update/read/forget/no-op) or recognized two-action pair (create-then-delete, delete-then-create, create-then-forget). The default case panics, joining the slice into the message. This is an invariant violation: a valid plan JSON only ever contains the enumerated action sets produced by the matching `actionString` encoder.
Source
Thrown at internal/command/jsonplan/plan.go:1030
if len(actions) == 1 {
switch actions[0] {
case "create":
return plans.Create
case "delete":
return plans.Delete
case "update":
return plans.Update
case "read":
return plans.Read
case "forget":
return plans.Forget
case "no-op":
return plans.NoOp
}
}
panic("unrecognized action slice: " + strings.Join(actions, ", "))
}
// encodePaths lossily encodes a cty.PathSet into an array of arrays of step
// values, such as:
//
// [["length"],["triggers",0,"value"]]
//
// The lossiness is that we cannot distinguish between an IndexStep with string
// key and a GetAttr step. This is fine with JSON output, because JSON's type
// system means that those two steps are equivalent anyway: both are object
// indexes.
//
// JavaScript (or similar dynamic language) consumers of these values can
// iterate over the steps starting from the root object to reach the
// value that each path is describing.
func encodePaths(pathSet cty.PathSet) (json.RawMessage, error) {
if pathSet.Empty() {
return nil, nilView on GitHub (pinned to c9def3e214)
Solutions
- Regenerate the plan with the same Terraform binary that will apply it.
- If you produce/consume plan JSON programmatically, restrict actions to the known set: create, delete, update, read, forget, no-op, and the pairs [create,delete]/[delete,create]/[create,forget].
- Treat plan files as opaque artifacts; do not edit action arrays by hand.
- Report a bug if reproduced with stock Terraform and an untouched plan.
Example fix
// before: validating a plan JSON consumer by trusting actions
func toPlanAction(actions []string) plans.Action {
return jsonplan.UnmarshalActions(actions) // panics on unknown
}
// after: pre-validate against the known allow-list
var validActions = map[string]bool{"create": true, "delete": true, "update": true, "read": true, "forget": true, "no-op": true}
func toPlanAction(actions []string) (plans.Action, error) {
for _, a := range actions {
if !validActions[a] {
return 0, fmt.Errorf("unrecognized action %q; regenerate plan", a)
}
}
return jsonplan.UnmarshalActions(actions)
} Defensive patterns
Strategy: validation
Validate before calling
// Go: pre-validate action slices before calling UnmarshalActions
var validSingle = map[string]bool{"create": true, "delete": true, "update": true, "read": true, "forget": true, "no-op": true}
func safeUnmarshal(actions []string) (plans.Action, error) {
for _, a := range actions {
if !validSingle[a] {
return 0, fmt.Errorf("unrecognized action %q in plan; regenerate with current terraform", a)
}
}
return jsonplan.UnmarshalActions(actions)
} Try / catch
// Go: recover from the jsonplan panic
defer func() {
if r := recover(); r != nil {
action = plans.NoOp
err = fmt.Errorf("failed to decode actions %v: %v", actions, r)
}
}()
action := jsonplan.UnmarshalActions(actions) Prevention
- Only consume plans produced by the same Terraform version.
- When generating plan JSON programmatically, restrict actions to the known enum/pairs.
- Never edit `change.actions` arrays manually.
- Pin Terraform versions across plan/apply environments.
When it happens
Trigger: Reading or applying a JSON plan whose `resource_changes[].change.actions` array contains an unknown action token or an unrecognized 2-element ordering. Typically a version-incompatible plan, a hand-crafted JSON plan, or tooling that emitted a typo'd/garbage action string.
Common situations: Forward-generating a plan with a newer Terraform that adds an action type (e.g. a new lifecycle verb) and consuming it with an older binary; corrupted plan artifact; custom automation that synthesizes plan JSON.
Related errors
- found unrecognized resource mode:
- unsupported action %q
- found unrecognized resource mode:
- Workspace data missing from plan file. Current workspace is
- This run has no required providers information provided at a
AI-assisted analysis of hashicorp/terraform@c9def3e214 (2026-08-07).
Data as JSON: /api/errors/33d64d0b26cc0781.
Report an issue: GitHub.