hashicorp/terraform · error
argument must be a list or tuple
Error message
argument must be a list or tuple
What it means
Thrown by the `index()` function (IndexFunc) in its Impl when the first argument's type is neither a list nor a tuple. index() searches an ordered sequence for a value and returns its numeric position, so non-sequence inputs (maps, sets, strings, scalars) are invalid. The check runs before any unknown-value handling.
Solutions
- Ensure the first argument is a list(...) or tuple. Convert with `tolist(...)` if needed.
- For key-based access use `lookup()` or `local.map[key]` instead of index().
- If the source is a set and order matters, materialize an ordered list.
Example fix
// before
locals { i = index(var.tags_map, "env") } # map passed
// after
locals { i = index(var.tags_list, "env") } # list(string) Defensive patterns
Strategy: validation
Validate before calling
# HCL: check the first arg is a list/tuple
locals { i = can(length(var.input)) && try(tolist(var.input), null) != null ? index(var.input, target) : -1 } Type guard
# HCL: convert to list explicitly
locals { i = index(tolist(var.input), target) } Prevention
- Distinguish index() (list position) from lookup()/map indexing (key).
- Declare variables as list(...) not set(...) when order matters.
- Add `terraform validate` in CI.
When it happens
Trigger: Calling `index()` with a non-list first argument: `index({a=1,b=2}, 1)`, `index(var.amap, key)`, or `index("abc", "b")`. Sets are also rejected because they are unordered.
Common situations: Confusing index() (position in list) with lookup() (key in map). Passing a set where ordering is required. Mistyping a variable from list to set during refactor.
Related errors
- argument must be a string, a collection type, or a…
- cannot search an empty list
- input must be a map of lists of strings
- item not found
- all arguments must have the same type
AI-assisted analysis of hashicorp/terraform@d32a084675 (2026-08-11).
Data as JSON: /api/errors/65449b70a249ae3c.
Report an issue: GitHub.
Appendix: source
Thrown at internal/lang/funcs/collection.go:193
})
// IndexFunc constructs a function that finds the element index for a given value in a list.
var IndexFunc = function.New(&function.Spec{
Params: []function.Parameter{
{
Name: "list",
Type: cty.DynamicPseudoType,
},
{
Name: "value",
Type: cty.DynamicPseudoType,
},
},
Type: function.StaticReturnType(cty.Number),
RefineResult: refineNotNull,
Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) {
if !(args[0].Type().IsListType() || args[0].Type().IsTupleType()) {
return cty.NilVal, errors.New("argument must be a list or tuple")
}
if !args[0].IsKnown() {
return cty.UnknownVal(cty.Number), nil
}
if args[0].LengthInt() == 0 { // Easy path
return cty.NilVal, errors.New("cannot search an empty list")
}
for it := args[0].ElementIterator(); it.Next(); {
i, v := it.Element()
eq, err := stdlib.Equal(v, args[1])
if err != nil {
return cty.NilVal, err
}
if !eq.IsKnown() {
return cty.UnknownVal(cty.Number), nilView on GitHub (pinned to d32a084675)