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, nil

View on GitHub (pinned to c9def3e214)

Solutions

  1. Regenerate the plan with the same Terraform binary that will apply it.
  2. 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].
  3. Treat plan files as opaque artifacts; do not edit action arrays by hand.
  4. 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

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


AI-assisted analysis of hashicorp/terraform@c9def3e214 (2026-08-07). Data as JSON: /api/errors/33d64d0b26cc0781. Report an issue: GitHub.