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(), nilView on GitHub (pinned to c9def3e214)
Solutions
- Pass exactly 2 or 3 arguments: lookup(map, key) or lookup(map, key, default).
- For multiple fallbacks, nest lookups or use coalesce/try: coalesce(lookup(m,"a"), lookup(m,"b"), "default").
- Audit generated/templated lookup calls for stray extra arguments.
- 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
- Pass exactly 2 or 3 args to lookup.
- Use coalesce()/try() for multiple fallbacks, not extra positional args.
- Lint generated lookup calls for stray arguments.
- Document the lookup signature in module readmes.
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
- lookup failed to find key %s
- invalid CIDR expression: %s
- IPv6 addresses cannot have a netmask: %s
- Unknown validation type: %#v
- empty state name
AI-assisted analysis of hashicorp/terraform@c9def3e214 (2026-08-07).
Data as JSON: /api/errors/a71e12435e1ae6dc.
Report an issue: GitHub.