hashicorp/terraform · error

lookup() takes two or three arguments, got

Error message

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

What it means

lookup() type-check error: the HCL lookup() function accepts exactly two mandatory arguments (map, key) plus an optional third (default). The function's Type callback rejects arg counts outside [1,3] -- but note the message says 'two or three arguments, got N' while the actual gate is len(args) < 1 || len(args) > 3, so it triggers on 0 args or >3 args (the message wording reflects the expected end-user signature, not the raw check).

Solutions

  1. Use exactly lookup(map, key) or lookup(map, key, default).
  2. Remove extra positional arguments; if multiple defaults are needed, combine them with coalesce inside the default slot.

Example fix

// before
val = lookup(var.map, "k", var.def1, var.def2)

// after
val = lookup(var.map, "k", coalesce(var.def1, var.def2))
Defensive patterns

Strategy: validation

Validate before calling

// Use exactly the supported arity.
locals { v = length([var.map, var.key]) == 2 ? lookup(var.map, var.key) : lookup(var.map, var.key, var.default) }

Prevention

When it happens

Trigger: Calling lookup() with zero arguments, or with more than three arguments (e.g. lookup(map, key, default1, default2)). The VarParam absorbs extras only up to the internal cap of 3.

Common situations: Wrong number of trailing commas, a splat/for-expression that produced too many positional args, copy-paste adding an extra default value.

Related errors


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

Appendix: 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 d32a084675)