hashicorp/terraform · error

all arguments must have the same type

Error message

all arguments must have the same type

What it means

Thrown by the `coalesce()` function (CoalesceFunc) during its Type callback when convert.UnifyUnsafe over all variadic argument types yields cty.NilType — meaning the arguments cannot be unified to a single common type. coalesce must return one concrete type, so heterogeneous types that cannot convert to each other are rejected before evaluation.

Solutions

  1. Make every coalesce() argument the same type, or types that auto-convert (e.g. all strings, all numbers).
  2. Add explicit type conversion: `coalesce(tostring(var.x), "default")`.
  3. Split logic: use separate coalesce calls per type or a lookup map keyed by a discriminator.

Example fix

// before
locals { x = coalesce(var.name, 0) }   # string vs number

// after
locals { x = coalesce(var.name, "default") }
Defensive patterns

Strategy: validation

Validate before calling

# HCL: ensure all coalesce args share a type before the call
locals {
  args = [var.a, var.b, var.c]
  ok   = alltrue([for v in local.args : try(tostring(v), null) != null])
  out  = local.ok ? coalesce([for v in local.args : tostring(v)]...) : "default"
}

Type guard

# HCL: normalize all args to one type first
locals { out = coalesce(tostring(var.a), tostring(var.b), "default") }

Prevention

When it happens

Trigger: Calling `coalesce()` with arguments of incompatible cty types, e.g. `coalesce("a", 1)` (string vs number) or `coalesce([1], {a=1})`. The Type func collects all arg types; if UnifyUnsafe fails it returns NilType and this error.

Common situations: Mixing a string default with a number variable, e.g. `coalesce(var.env, 0)`. Using coalesce on list/object args of differing element shapes. Copying an example that assumed homogeneous types into a config with mixed types.

Related errors


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

Appendix: source

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

// stdlib and modified so that it returns the first *non-empty* non-null element
// from a sequence, instead of merely the first non-null.
var CoalesceFunc = function.New(&function.Spec{
	Params: []function.Parameter{},
	VarParam: &function.Parameter{
		Name:             "vals",
		Type:             cty.DynamicPseudoType,
		AllowUnknown:     true,
		AllowDynamicType: true,
		AllowNull:        true,
	},
	Type: func(args []cty.Value) (ret cty.Type, err error) {
		argTypes := make([]cty.Type, len(args))
		for i, val := range args {
			argTypes[i] = val.Type()
		}
		retType, _ := convert.UnifyUnsafe(argTypes)
		if retType == cty.NilType {
			return cty.NilType, errors.New("all arguments must have the same type")
		}
		return retType, nil
	},
	RefineResult: refineNotNull,
	Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) {
		for _, argVal := range args {
			// We already know this will succeed because of the checks in our Type func above
			argVal, _ = convert.Convert(argVal, retType)
			if !argVal.IsKnown() {
				return cty.UnknownVal(retType), nil
			}
			if argVal.IsNull() {
				continue
			}
			if retType == cty.String && argVal.RawEquals(cty.StringVal("")) {
				continue
			}

View on GitHub (pinned to d32a084675)