opentofu/opentofu · error

ephemeral resource %q detected in the plan. This is an error

Error message

ephemeral resource %q detected in the plan. This is an error in OpenTofu

What it means

While marshaling planned values for `tofu show -json` (jsonplan.marshalPlanResources), a resource change whose address has EphemeralResourceMode is refused. Ephemeral resources (managed via ephemeral blocks) are never persisted nor included in planned-change output, so encountering one in the changes set violates a core invariant — the message itself states 'This is an error in OpenTofu'.

Source

Thrown at internal/command/jsonplan/values.go:208

		if r.Action == plans.Delete {
			continue
		}

		resource := Resource{
			Address:      r.Addr.String(),
			Type:         r.Addr.Resource.Resource.Type,
			Name:         r.Addr.Resource.Resource.Name,
			ProviderName: r.ProviderAddr.Provider.String(),
			Index:        r.Addr.Resource.Key,
		}

		switch r.Addr.Resource.Resource.Mode {
		case addrs.ManagedResourceMode:
			resource.Mode = "managed"
		case addrs.DataResourceMode:
			resource.Mode = "data"
		case addrs.EphemeralResourceMode:
			return ret, fmt.Errorf("ephemeral resource %q detected in the plan. This is an error in OpenTofu", r.Addr.String())
		default:
			return nil, fmt.Errorf("resource %s has an unsupported mode %s",
				r.Addr.String(),
				r.Addr.Resource.Resource.Mode.String(),
			)
		}

		schema, schemaVer := schemas.ResourceTypeConfig(
			r.ProviderAddr.Provider,
			r.Addr.Resource.Resource.Mode,
			resource.Type,
		)
		if schema == nil {
			return nil, fmt.Errorf("no schema found for %s", r.Addr.String())
		}
		resource.SchemaVersion = schemaVer
		changeV, err := r.Decode(schema)
		if err != nil {

View on GitHub (pinned to 3561785c48)

Solutions

  1. If you are on a development or unreleased build, switch to the latest stable OpenTofu release.
  2. If you embed the engine, filter ephemeral-mode changes out of plans.Changes before calling jsonplan.Marshal.
  3. If it reproduces on a stable release, report it to the OpenTofu maintainers with the config and plan — the message explicitly asks for it.

Example fix

// before (embedding code): marshaling changes that may include ephemeral resources
planJSON, err := jsonplan.Marshal(plan, schemas)

// after: strip ephemeral-mode changes before marshaling
filtered := filterEphemeral(plan.Changes)
planJSON, err := jsonplan.Marshal(planWithChanges(filtered), schemas)
Defensive patterns

Strategy: validation

Validate before calling

// drop ephemeral-mode changes before handing plans.Changes to jsonplan (embedding code)
func withoutEphemeral(changes []*plans.ResourceInstanceChangeSrc) []*plans.ResourceInstanceChangeSrc {
	out := changes[:0]
	for _, c := range changes {
		if c.Addr.Resource.Resource.Mode != addrs.EphemeralResourceMode {
			out = append(out, c)
		}
	}
	return out
}

Type guard

func isEphemeralChange(c *plans.ResourceInstanceChangeSrc) bool {
	return c.Addr.Resource.Resource.Mode == addrs.EphemeralResourceMode
}

Prevention

When it happens

Trigger: Calling jsonplan.Marshal (directly or via `tofu show -json` / `tofu show -json plan.tfplan`) on a plans.Changes that contains a ResourceInstanceChangeSrc for an ephemeral resource address (addrs.EphemeralResourceMode). Upstream plan walking normally excludes ephemeral resources, so this requires a defect in plan construction or a programmatically assembled changes set.

Common situations: Ordinary CLI users do not hit this. It can appear when running a dev/nightly OpenTofu build with a regression in ephemeral-resource handling, or when code that embeds OpenTofu puts ephemeral resources into plans.Changes manually.

Related errors


AI-assisted analysis of opentofu/opentofu@3561785c48 (2026-08-15). Data as JSON: /api/errors/ff5955060026dd8e. Report an issue: GitHub.