hashicorp/terraform · error

cannot decode from flatmap

Error message

cannot decode %s from flatmap

What it means

Returned by hcl2ValueFromFlatmapValue when the target cty.Type does not match any handled branch (primitive, object, tuple, map, list, set). The function dispatches on type kind; reaching the default branch means the type is either cty.DynamicPseudoType, a nested dynamic, or an unrecognized type object — none of which can be decoded from the legacy flatmap (key/value string) representation.

Solutions

  1. Confirm the Type passed in is one of: primitive, object, tuple, map, list, or set — and that it is not cty.DynamicPseudoType at the top level.
  2. If the source data is genuinely dynamic, decode it as cty.String and convert afterwards instead of asking the shim to infer the type.
  3. For state migration, run through the proper state upgrader chain so the schema matches the data being decoded.
  4. Reproduce with a minimal flatmap + type pair to confirm which kind is falling through, then widen the switch if a legitimate new kind is required.

Example fix

// before — decoding a dynamic-typed slot from flatmap
val, err := hcl2shim.hcl2ValueFromFlatmapValue(flatmap, "attr", cty.DynamicPseudoType)

// after — decode as concrete type, or skip the shim for dynamic slots
val, err := hcl2shim.hcl2ValueFromFlatmapValue(flatmap, "attr", cty.String)
Defensive patterns

Strategy: type-guard

Validate before calling

func isDecodableFromFlatmap(ty cty.Type) bool {
    return ty.IsPrimitiveType() || ty.IsObjectType() || ty.IsTupleType() ||
        ty.IsMapType() || ty.IsListType() || ty.IsSetType()
}

Type guard

func isDecodableFromFlatmap(ty cty.Type) bool {
    if ty == cty.DynamicPseudoType { return false }
    return ty.IsPrimitiveType() || ty.IsObjectType() || ty.IsTupleType() ||
        ty.IsMapType() || ty.IsListType() || ty.IsSetType()
}

Prevention

When it happens

Trigger: Calling hcl2ValueFromFlatmapValue (directly or via the flatmap round-trip helpers) with a Type whose top-level kind is dynamic or a recently added cty kind that the shim does not know. Most often reached during state migration or when shimming a v3 state schema into a typed cty value.

Common situations: State files written by an older Terraform version being read by newer code where a schema attribute became cty.DynamicPseudoType; custom flatmap producers (some external tools) emitting keys the shim cannot map; testing harnesses that feed synthetic flatmaps with mismatched types.

Related errors


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

Appendix: source

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

func hcl2ValueFromFlatmapValue(m map[string]string, key string, ty cty.Type) (cty.Value, error) {
	var val cty.Value
	var err error
	switch {
	case ty.IsPrimitiveType():
		val, err = hcl2ValueFromFlatmapPrimitive(m, key, ty)
	case ty.IsObjectType():
		val, err = hcl2ValueFromFlatmapObject(m, key+".", ty.AttributeTypes())
	case ty.IsTupleType():
		val, err = hcl2ValueFromFlatmapTuple(m, key+".", ty.TupleElementTypes())
	case ty.IsMapType():
		val, err = hcl2ValueFromFlatmapMap(m, key+".", ty)
	case ty.IsListType():
		val, err = hcl2ValueFromFlatmapList(m, key+".", ty)
	case ty.IsSetType():
		val, err = hcl2ValueFromFlatmapSet(m, key+".", ty)
	default:
		err = fmt.Errorf("cannot decode %s from flatmap", ty.FriendlyName())
	}

	if err != nil {
		return cty.DynamicVal, err
	}
	return val, nil
}

func hcl2ValueFromFlatmapPrimitive(m map[string]string, key string, ty cty.Type) (cty.Value, error) {
	rawVal, exists := m[key]
	if !exists {
		return cty.NullVal(ty), nil
	}
	if rawVal == UnknownVariableValue {
		return cty.UnknownVal(ty), nil
	}

	var err error

View on GitHub (pinned to d32a084675)