opentofu/opentofu · error

ephemeral resources are not meant to be processed by this fu

Error message

ephemeral resources are not meant to be processed by this function. Are you sure that this code should be reused?

What it means

NewInstanceInfo panics when given a resource in addrs.EphemeralResourceMode. Ephemeral resources postdate the legacy provider protocols that InstanceInfo serves and never flow through legacy diff/state machinery; the panic message itself asks whether the code path should be reused for them.

Source

Thrown at internal/legacy/tofu/resource.go:130

	path := make([]string, len(addr.Module))
	for i, step := range addr.Module {
		if step.InstanceKey != addrs.NoKey {
			panic("NewInstanceInfo cannot convert module instance with key")
		}
		path[i] = step.Name
	}

	// This is a funny old meaning of "id" that is no longer current. It should
	// not be used for anything users might see. Note that it does not include
	// a representation of the resource mode, and so it's impossible to
	// determine from an InstanceInfo alone whether it is a managed or data
	// resource that is being referred to.
	id := fmt.Sprintf("%s.%s", addr.Resource.Resource.Type, addr.Resource.Resource.Name)
	if addr.Resource.Resource.Mode == addrs.DataResourceMode {
		id = "data." + id
	}
	if addr.Resource.Resource.Mode == addrs.EphemeralResourceMode {
		panic("ephemeral resources are not meant to be processed by this function. Are you sure that this code should be reused?")
	}
	if addr.Resource.Key != addrs.NoKey {
		switch k := addr.Resource.Key.(type) {
		case addrs.IntKey:
			id = id + fmt.Sprintf(".%d", int(k))
		default:
			panic(fmt.Sprintf("NewInstanceInfo cannot convert resource instance with %T instance key", addr.Resource.Key))
		}
	}

	return &InstanceInfo{
		Id:         id,
		ModulePath: path,
		Type:       addr.Resource.Resource.Type,
	}
}

// ResourceAddress returns the address of the resource that the receiver is describing.

View on GitHub (pinned to 3561785c48)

Solutions

  1. Branch on addr.Resource.Resource.Mode before calling and handle ephemeral resources on modern code paths only
  2. Do not route ephemeral resources through legacy tofu types; use providers/addrs modern APIs instead
  3. If the panic fired, treat it as a design signal: this legacy function must not be reused for the new mode

Example fix

// before
info := NewInstanceInfo(instAddr)

// after
if instAddr.Resource.Resource.Mode == addrs.EphemeralResourceMode {
	return nil, fmt.Errorf("ephemeral resource %s must not use legacy InstanceInfo", instAddr)
}
info := NewInstanceInfo(instAddr)
Defensive patterns

Strategy: type-guard

Type guard

func isEphemeralResource(a addrs.AbsResourceInstance) bool {
	return a.Resource.Resource.Mode == addrs.EphemeralResourceMode
}

Prevention

When it happens

Trigger: Passing an AbsResourceInstance whose Resource.Resource.Mode is addrs.EphemeralResourceMode into NewInstanceInfo — typically generic address-formatting or logging code that handles all resource modes uniformly.

Common situations: Adding ephemeral resource support to a codebase that already calls NewInstanceInfo; refactoring shared helpers that enumerate resources of every mode; new provider features routed through legacy plumbing by mistake.

Related errors


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