hashicorp/terraform · error

invalid count value for %q in state: %s

Error message

invalid count value for %q in state: %s

What it means

Returned by hcl2ValueFromFlatmapTuple (flatmap.go:237) when the count marker string stored at prefix+"#" in the flatmap is not parseable as an integer via strconv.Atoi. In legacy flatmap, tuple/list containers store their length in a special '#'-suffixed key; a non-numeric value there means the state is corrupt or was written by incompatible code.

Source

Thrown at internal/configs/hcl2shim/flatmap.go:237

	var vals []cty.Value

	// if the container is unknown, there is no count string
	listName := strings.TrimRight(prefix, ".")
	if m[listName] == UnknownVariableValue {
		return cty.UnknownVal(cty.Tuple(etys)), nil
	}

	countStr, exists := m[prefix+"#"]
	if !exists {
		return cty.NullVal(cty.Tuple(etys)), nil
	}
	if countStr == UnknownVariableValue {
		return cty.UnknownVal(cty.Tuple(etys)), nil
	}

	count, err := strconv.Atoi(countStr)
	if err != nil {
		return cty.DynamicVal, fmt.Errorf("invalid count value for %q in state: %s", prefix, err)
	}
	if count != len(etys) {
		return cty.DynamicVal, fmt.Errorf("wrong number of values for %q in state: got %d, but need %d", prefix, count, len(etys))
	}

	vals = make([]cty.Value, len(etys))
	for i, ety := range etys {
		key := prefix + strconv.Itoa(i)
		val, err := hcl2ValueFromFlatmapValue(m, key, ety)
		if err != nil {
			return cty.DynamicVal, err
		}
		vals[i] = val
	}
	return cty.TupleVal(vals), nil
}

func hcl2ValueFromFlatmapMap(m map[string]string, prefix string, ty cty.Type) (cty.Value, error) {

View on GitHub (pinned to c9def3e214)

Solutions

  1. Inspect the state file at the key reported in the message (it is the prefix); ensure the '#'-suffixed entry is a non-negative integer.
  2. If the container should be empty/unknown, set the count to "0" or remove stale keys so the earlier guards handle it.
  3. If the schema type changed, add a state migration to rewrite the length key before decoding.
  4. Regenerate the state by re-applying or re-importing the resource if the flatmap is unrecoverable.

Example fix

// before — state has: "config.#": "three"

// after — flatmap length keys must be integers
"config.#": "3"
Defensive patterns

Strategy: validation

Validate before calling

// Verify a tuple/list count key is a valid integer before decoding
func validFlatmapCount(m map[string]string, prefix string) bool {
    s, ok := m[prefix+"#"]
    if !ok || s == hcl2shim.UnknownVariableValue {
        return true
    }
    n, err := strconv.Atoi(s)
    return err == nil && n >= 0
}

Type guard

func isIntegerCount(s string) bool {
    if s == hcl2shim.UnknownVariableValue {
        return true
    }
    n, err := strconv.Atoi(s)
    return err == nil && n >= 0
}

Prevention

When it happens

Trigger: Decoding a tuple-typed attribute from flatmap where the '<prefix>#' key holds a non-integer string (e.g. empty, a word, or UnknownVariableValue that bypassed the earlier guard). Triggered during state read/refresh/import when the schema declares a tuple type.

Common situations: Hand-edited state files where a '#'-suffixed length key was altered. A schema changed from list to tuple (or vice versa) and the count key format changed. State written by a much older/newer Terraform version with a different flatmap convention.

Related errors


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