hashicorp/terraform · error

action schema not found for action

Error message

action schema not found for action %q

What it means

Returned by the tfplugin5 PlanAction handler when the requested action type is absent from p.schema.Actions. Terraform core asked to plan an action the provider never declared, so the wrapper cannot find a config schema to decode the proposed action data.

Solutions

  1. Verify the action type spelling in configuration matches the provider.
  2. Confirm via `terraform providers schema -json` that the provider advertises the action.
  3. Upgrade the provider to a version declaring the action.
  4. If developing the provider, register the action in schema.Actions.

Example fix

// before
providerSchema.Actions = map[string]*config.Action{}
// after
providerSchema.Actions = map[string]*config.Action{
    "example/delete": exampleActionSchema,
}
Defensive patterns

Strategy: validation

Validate before calling

// Confirm the action is registered before planning it.
schemas, err := client.GetProviderSchema(ctx, &tfplugin5.GetProviderSchema_Request{})
if err != nil {
    return err
}
if _, ok := schemas.Actions[actionType]; !ok {
    return fmt.Errorf("will not plan action: %q not registered by provider", actionType)
}
return client.PlanAction(ctx, actionType, config)

Type guard

func actionRegistered(s *tfplugin5.GetProviderSchema_Response, actionType string) bool {
    _, ok := s.Actions[actionType]
    return ok
}

Prevention

When it happens

Trigger: A PlanAction RPC whose req.ActionType is missing from p.schema.Actions; the map lookup returns ok=false.

Common situations: Provider version without action support or without this specific action; action type name typo in config; terraform core version that expects an action the running provider does not expose.

Related errors


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

Appendix: source

Thrown at internal/grpcwrap/provider.go:855

			displayName = item.GetAttr("display_name").AsString()
		}

		res.Send(&tfplugin5.ListResource_Event{
			Identity:       &tfplugin5.ResourceIdentityData{IdentityData: identityVal},
			ResourceObject: stateVal,
			DisplayName:    displayName,
		})
	}

	return nil
}

func (p *provider) PlanAction(_ context.Context, req *tfplugin5.PlanAction_Request) (*tfplugin5.PlanAction_Response, error) {
	resp := &tfplugin5.PlanAction_Response{}

	actionSchema, ok := p.schema.Actions[req.ActionType]
	if !ok {
		return nil, fmt.Errorf("action schema not found for action %q", req.ActionType)
	}

	ty := actionSchema.ConfigSchema.ImpliedType()
	configVal, err := decodeDynamicValue(req.Config, ty)
	if err != nil {
		resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
		return resp, nil
	}

	planResp := p.provider.PlanAction(providers.PlanActionRequest{
		ActionType:         req.ActionType,
		ProposedActionData: configVal,
		ClientCapabilities: providers.ClientCapabilities{
			DeferralAllowed:            true,
			WriteOnlyAttributesAllowed: true,
			ComputedBlocksAllowed:      true,
		},
	})

View on GitHub (pinned to d32a084675)