hashicorp/terraform · error

invalid count value for

Error message

invalid count value for %q in state: %s

What it means

Returned by hcl2ValueFromFlatmapTuple when the '<prefix>#' sentinel key (the legacy flatmap count marker) holds a value that strconv.Atoi cannot parse as an integer. The flatmap tuple representation stores element count under a trailing '#' key; if that marker is non-numeric, the decoder cannot know how many elements to read and aborts.

Solutions

  1. Inspect the state key named in the error and confirm the trailing '#' marker holds an integer string.
  2. Restore from a known-good state backup if the marker is corrupt.
  3. If migrating from a non-flatmap representation, ensure the producer writes the '#' count sentinel as an integer for tuple/list/set types.
  4. Run 'terraform state pull' / 'terraform state push' to round-trip and normalize the state.

Example fix

// operational — not a code fix
// before: "root.tuple.#": "three"  (non-numeric)
// after:  "root.tuple.#": "3"
Defensive patterns

Strategy: validation

Validate before calling

func tupleCountIsInteger(m map[string]string, prefix string) bool {
    s, ok := m[prefix+"#"]
    if !ok { return true } // missing -> null, not an error
    _, err := strconv.Atoi(s)
    return err == nil
}

Prevention

When it happens

Trigger: Decoding a tuple-typed value from a flatmap where the count sentinel (e.g. 'root.0.field.#') is missing-as-string, empty, or contains non-digit characters. Reached via the flatmap-to-cty shim during state read or diff application.

Common situations: Corrupt or hand-edited state where the count sentinel was overwritten; flatmap producers that emit 'count' or 'len' under a different key than '#'; partial state writes that left the count marker empty during a crash.

Related errors


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

Appendix: 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 d32a084675)