hashicorp/terraform · critical

NewInstanceInfo cannot convert resource instance with %T ins

Error message

NewInstanceInfo cannot convert resource instance with %T instance key

What it means

Panics in NewInstanceInfo (resource.go:81). The legacy type can only represent resource instances with NoKey or IntKey (count); a string key produced by for_each hits the default branch and panics.

Source

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

		}
		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:
			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,
	}
}

// ResourceConfig is a legacy type that was formerly used to represent
// interpolatable configuration blocks. It is now only used to shim to old
// APIs that still use this type, via NewResourceConfigShimmed.
type ResourceConfig struct {
	ComputedKeys []string
	Raw          map[string]interface{}
	Config       map[string]interface{}
}

View on GitHub (pinned to c9def3e214)

Solutions

  1. Upgrade the provider/SDK so the resource no longer goes through legacy InstanceInfo.
  2. Replace for_each with count (integer keys) on the affected resource.
  3. Reorganize the config so the resource is not in a for_each block.

Example fix

// before
resource "x" "y" { for_each = toset(["a","b"]) }
// after
resource "x" "y" { count = 2 }
Defensive patterns

Strategy: validation

Validate before calling

func resourceKeyLegacyOk(addr addrs.AbsResourceInstance) error {
    switch k := addr.Resource.Key.(type) {
    case addrs.NoKey, addrs.IntKey: return nil
    default: return fmt.Errorf("resource instance key %T unsupported by legacy InstanceInfo", k)
    }
}

Type guard

func isLegacyCompatibleKey(k addrs.InstanceKey) bool {
    switch k.(type) {
    case addrs.NoKey, addrs.IntKey: return true
    }
    return false
}

Prevention

When it happens

Trigger: A resource created with `for_each` (string keys) is routed through the legacy InstanceInfo path.

Common situations: An older provider/SDK used with for_each on a managed resource that exercises legacy code paths.

Related errors


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