hashicorp/terraform · critical

invalid index value %q

Error message

invalid index value %q

What it means

Panics in countFlatmapContainerValues (diff.go:584). The function counts flatmap container values and requires the key to end in '.#' (list/set count) or '.%' (map count); any other key (a plain attribute or an element key like 'ports.0') panics. It is an internal precondition violation in the diff-application code.

Source

Thrown at internal/legacy/terraform/diff.go:584

	childName := path[len(path)-1]
	containerSchema := &configschema.Block{
		BlockTypes: map[string]*configschema.NestedBlock{
			childName: {
				Nesting: configschema.NestingSet,
				Block:   *synthSchema,
			},
		},
	}

	return d.applyBlockDiff(parentPath, attrs, containerSchema)
}

// countFlatmapContainerValues returns the number of values in the flatmapped container
// (set, map, list) indexed by key. The key argument is expected to include the
// trailing ".#", or ".%".
func countFlatmapContainerValues(key string, attrs map[string]string) string {
	if len(key) < 3 || !(strings.HasSuffix(key, ".#") || strings.HasSuffix(key, ".%")) {
		panic(fmt.Sprintf("invalid index value %q", key))
	}

	prefix := key[:len(key)-1]
	items := map[string]int{}

	for k := range attrs {
		if k == key {
			continue
		}
		if !strings.HasPrefix(k, prefix) {
			continue
		}

		suffix := k[len(prefix):]
		dot := strings.Index(suffix, ".")
		if dot > 0 {
			suffix = suffix[:dot]
		}

View on GitHub (pinned to c9def3e214)

Solutions

  1. Inspect the key printed in the panic message; it must be a count key (.# or .%).
  2. Restore a known-good state and re-run plan/apply.
  3. If seen after a provider/TF upgrade, report the diff bug with the offending flatmap key.
Defensive patterns

Strategy: validation

Validate before calling

func isContainerCountKey(k string) bool {
    return strings.HasSuffix(k, ".#") || strings.HasSuffix(k, ".%")
}

Try / catch

// guard internal callers with recover at the diff boundary
defer func() {
    if r := recover(); r != nil {
        diag := fmt.Errorf("internal diff panic: %v", r)
        _ = diag // surface as a diagnostic
    }
}()

Prevention

When it happens

Trigger: An internal caller passes a non-count flatmap key to countFlatmapContainerValues, reached during diff expansion of sets/lists/maps. Usually a bug in diff construction or malformed flatmap keys.

Common situations: Corrupted diff/state, custom flatmap manipulation, or schema migration producing malformed keys that look like element keys instead of count keys.

Related errors


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