hashicorp/terraform · error

lookup() takes two or three arguments, got %d

Error message

lookup() takes two or three arguments, got %d

What it means

Returned by the lookup built-in's Type function (LookupFunc, internal/lang/funcs/collection.go:248) when the number of arguments is outside the accepted 2-or-3 range. lookup takes inputMap + key (2 params) plus an optional default (variadic); passing more than one default value (4+ total args) violates the Type check len(args) > 3 and yields this arity error before any value work happens.

Source

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

		},
		{
			Name:         "key",
			Type:         cty.String,
			AllowMarked:  true,
			AllowUnknown: true,
		},
	},
	VarParam: &function.Parameter{
		Name:             "default",
		Type:             cty.DynamicPseudoType,
		AllowUnknown:     true,
		AllowDynamicType: true,
		AllowNull:        true,
		AllowMarked:      true,
	},
	Type: func(args []cty.Value) (ret cty.Type, err error) {
		if len(args) < 1 || len(args) > 3 {
			return cty.NilType, fmt.Errorf("lookup() takes two or three arguments, got %d", len(args))
		}

		ty := args[0].Type()

		switch {
		case ty.IsObjectType():
			if !args[1].IsKnown() {
				return cty.DynamicPseudoType, nil
			}

			keyVal, _ := args[1].Unmark()
			key := keyVal.AsString()
			if ty.HasAttribute(key) {
				return args[0].GetAttr(key).Type(), nil
			} else if len(args) == 3 {
				// if the key isn't found but a default is provided,
				// return the default type
				return args[2].Type(), nil

View on GitHub (pinned to c9def3e214)

Solutions

  1. Pass exactly 2 or 3 arguments: lookup(map, key) or lookup(map, key, default).
  2. For multiple fallbacks, nest lookups or use coalesce/try: coalesce(lookup(m,"a"), lookup(m,"b"), "default").
  3. Audit generated/templated lookup calls for stray extra arguments.
  4. Prefer try() when you need graceful multi-key/default handling.

Example fix

# before (HCL)
v = lookup(var.tags, "env", "dev", "prod")  # 4 args -> lookup() takes two or three arguments, got 4

# after
v = lookup(var.tags, "env", "dev")
# multiple fallbacks:
v = coalesce(lookup(var.tags, "env"), lookup(var.tags, "environment"), "dev")
Defensive patterns

Strategy: validation

Validate before calling

# (HCL) enforce the 2-or-3 arg contract in a wrapper
locals {
  v = length([var.m, "k", "d"]) > 3 ? null : lookup(var.m, "k", "d")
}

Type guard

// (Go) true if lookup arg count is valid
func validLookupArity(n int) bool { return n == 2 || n == 3 }

Try / catch

# (HCL) use try/coalesce instead of extra positional defaults
value = coalesce(lookup(var.m, "a", ""), lookup(var.m, "b", ""), "default")

Prevention

When it happens

Trigger: Calling lookup(map, key, default, extra) (4 args) or otherwise passing more than the allowed set; the variadic default parameter collects surplus args beyond the two fixed params, and len(args) exceeds 3.

Common situations: Trying to supply multiple fallback values, misunderstanding lookup's signature as varargs, copy-paste adding an extra argument, or templating that injects an additional positional arg.

Related errors


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