hashicorp/terraform · critical

NewInstanceInfo cannot convert module instance with key

Error message

NewInstanceInfo cannot convert module instance with key

What it means

Panics by design in NewInstanceInfo (resource.go:62). The legacy InstanceInfo type cannot represent module instances created with count/for_each; if any module path step has a non-NoKey instance key, it panics. The docstring explicitly warns this path must be resolved before module count/for_each is supported.

Source

Thrown at internal/legacy/terraform/resource.go:62

//
// InstanceInfo is a legacy type, and uses of it should be gradually replaced
// by direct use of addrs.AbsResource or addrs.AbsResourceInstance as
// appropriate.
//
// The legacy InstanceInfo type cannot represent module instances with instance
// keys, so this function will panic if given such a path. Uses of this type
// should all be removed or replaced before implementing "count" and "for_each"
// arguments on modules in order to avoid such panics.
//
// This legacy type also cannot represent resource instances with string
// instance keys. It will panic if the given key is not either NoKey or an
// IntKey.
func NewInstanceInfo(addr addrs.AbsResourceInstance) *InstanceInfo {
	// We need an old-style []string module path for InstanceInfo.
	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.Key != addrs.NoKey {
		switch k := addr.Resource.Key.(type) {
		case addrs.IntKey:
			id = id + fmt.Sprintf(".%d", int(k))
		default:

View on GitHub (pinned to c9def3e214)

Solutions

  1. Upgrade the provider to a build against a newer SDK that no longer routes through legacy InstanceInfo.
  2. Avoid count/for_each on the module blocks that exercise the affected legacy provider path.
  3. Restructure: move the resource out of the counted module, or replicate the module manually.

Example fix

// before
module "svc" { count = var.n, source = "./svc" }
// after
module "svc_a" { source = "./svc" }
module "svc_b" { source = "./svc" }
Defensive patterns

Strategy: validation

Validate before calling

func noModuleInstanceKeys(addr addrs.AbsResourceInstance) error {
    for _, step := range addr.Module {
        if step.InstanceKey != addrs.NoKey {
            return fmt.Errorf("module %s has instance key; legacy InstanceInfo unsupported", step)
        }
    }
    return nil
}

Prevention

When it happens

Trigger: A provider using the legacy helper/schema ResourceData path is exercised against a module instance created with `count` or `for_each` on a module block, routing through NewInstanceInfo.

Common situations: Older SDK-based providers run under Terraform configurations that apply count/for_each to module blocks; SDK version lag.

Related errors


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