hashicorp/terraform · error

invalid collection length

Error message

invalid collection length: %s

What it means

one() function internal error: after computing the collection length and confirming it is known, gocty.FromCtyValue fails to convert the length cty number into a Go int. The code comment notes this is essentially impossible under normal operation -- it would indicate a bug in cty itself (length returned non-number/non-integer). End users effectively never see this; it surfaces only if a custom cty value breaks the length contract.

Solutions

  1. Treat this as a Terraform/cty bug: report it with the exact configuration and cty version.
  2. Verify the input to one() is a plain list/set (not a marked or proxy value).
  3. As a workaround, replace one() with explicit indexing: element[0].

Example fix

// before
locals { x = one(var.list) } // triggers pathological case

// after (workaround)
locals { x = length(var.list) == 1 ? var.list[0] : null }
Defensive patterns

Strategy: try-catch

Validate before calling

// Ensure the input is a plain list/set before calling one().
locals { ok = can(one(var.list)) ? one(var.list) : null }

Try / catch

v, err := funcs.OneFunc.Call([]cty.Value{listVal})
if err != nil {
    if strings.Contains(err.Error(), "invalid collection length") {
        // treat as a cty/terraform bug; report upstream
    }
}

Prevention

When it happens

Trigger: Calling one() on a list/set whose Length() returns a value that is not convertible to int (e.g. a number marked in a way that disrupts FromCtyValue, or a hand-constructed pathological cty value).

Common situations: Effectively unreachable in normal HCL; would only appear with custom function wrappers feeding malformed cty values into the standard one() function.

Related errors


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

Appendix: source

Thrown at internal/lang/funcs/collection.go:463

		ty := val.Type()

		// Our parameter spec above doesn't set AllowUnknown or AllowNull,
		// so we can assume our top-level collection is both known and non-null
		// in here.

		switch {
		case ty.IsListType() || ty.IsSetType():
			lenVal := val.Length()
			if !lenVal.IsKnown() {
				return cty.UnknownVal(retType), nil
			}
			var l int
			err := gocty.FromCtyValue(lenVal, &l)
			if err != nil {
				// It would be very strange to get here, because that would
				// suggest that the length is either not a number or isn't
				// an integer, which would suggest a bug in cty.
				return cty.NilVal, fmt.Errorf("invalid collection length: %s", err)
			}
			switch l {
			case 0:
				return cty.NullVal(retType), nil
			case 1:
				var ret cty.Value
				// We'll use an iterator here because that works for both lists
				// and sets, whereas indexing directly would only work for lists.
				// Since we've just checked the length, we should only actually
				// run this loop body once.
				for it := val.ElementIterator(); it.Next(); {
					_, ret = it.Element()
				}
				return ret, nil
			}
		case ty.IsTupleType():
			etys := ty.TupleElementTypes()
			switch len(etys) {

View on GitHub (pinned to d32a084675)