hashicorp/terraform · critical

unsupported operation type: %s This is a bug in Terraform a

Error message

unsupported operation type: %s

This is a bug in Terraform and should be reported. The local backend
is built-in to Terraform and should always support all operations.

What it means

Returned by Local.Operation when op.Type is not one of OperationTypeRefresh, OperationTypePlan, or OperationTypeApply. The message itself states this is a Terraform bug: the local backend is built-in and is expected to support every operation type, so reaching the default branch means the dispatch in core is broken or a new operation type was added without updating the local backend.

Source

Thrown at internal/backend/local/backend.go:314

// The given operation parameter will be merged with the ContextOpts on
// the structure with the following rules. If a rule isn't specified and the
// name conflicts, assume that the field is overwritten if set.
func (b *Local) Operation(ctx context.Context, op *backendrun.Operation) (*backendrun.RunningOperation, error) {
	if op.View == nil {
		panic("Operation called with nil View")
	}

	// Determine the function to call for our operation
	var f func(context.Context, context.Context, *backendrun.Operation, *backendrun.RunningOperation)
	switch op.Type {
	case backendrun.OperationTypeRefresh:
		f = b.opRefresh
	case backendrun.OperationTypePlan:
		f = b.opPlan
	case backendrun.OperationTypeApply:
		f = b.opApply
	default:
		return nil, fmt.Errorf(
			"unsupported operation type: %s\n\n"+
				"This is a bug in Terraform and should be reported. The local backend\n"+
				"is built-in to Terraform and should always support all operations.",
			op.Type)
	}

	// Lock
	b.opLock.Lock()

	// Build our running operation
	// the runninCtx is only used to block until the operation returns.
	runningCtx, done := context.WithCancel(context.Background())
	runningOp := &backendrun.RunningOperation{
		Context: runningCtx,
	}

	// stopCtx wraps the context passed in, and is used to signal a graceful Stop.
	stopCtx, stop := context.WithCancel(ctx)

View on GitHub (pinned to d32a084675)

Solutions

  1. File a bug report as the message instructs, including the op.Type value that was passed.
  2. If you are extending Terraform: add a case in the switch (backend.go:306) for the new operation type before it can reach this default.
  3. If calling Operation programmatically, ensure op.Type is set to one of the three valid constants.
  4. On a custom build, verify you are not running a binary where the local backend was patched to remove a case.

Example fix

null
Defensive patterns

Strategy: validation

Validate before calling

// Reject unsupported op types before calling Operation.
func supportedOp(t backendrun.OperationType) bool {
    switch t {
    case backendrun.OperationTypeRefresh, backendrun.OperationTypePlan, backendrun.OperationTypeApply:
        return true
    }
    return false
}

Type guard

null

Try / catch

// Operation returns (*RunningOperation, error); the unsupported-type case comes back as err.
rop, err := b.Operation(ctx, op)
if err != nil {
    if strings.Contains(err.Error(), "unsupported operation type") {
        panic("bug: op.Type = " + op.Type.String())
    }
    return err
}

Prevention

When it happens

Trigger: Operation is called with an op.Type outside the three handled cases (e.g. OperationTypeInvalid, or a newly added operation type). In normal CLI flows this should be unreachable because the command layer maps user commands onto the three supported types.

Common situations: Practically never in released Terraform. Can appear when developing a new operation type, when a fork/extension adds an operation without patching the local backend, or when Operation is invoked programmatically with an uninitialized op.Type.

Related errors


AI-assisted analysis of hashicorp/terraform@d32a084675 (2026-08-11). Data as JSON: /api/errors/562298781dd7a675. Report an issue: GitHub.