hashicorp/terraform · error
keys and searchset must be of the same type
Error message
keys and searchset must be of the same type
What it means
Thrown by MatchkeysFunc.Type (the HCL matchkeys() builtin). matchkeys(values, keys, searchset) requires keys and searchset to share a type; if convert.UnifyUnsafe fails on those two, the Type function rejects the call before any matching runs.
Source
Thrown at internal/lang/funcs/collection.go:352
var MatchkeysFunc = function.New(&function.Spec{
Params: []function.Parameter{
{
Name: "values",
Type: cty.List(cty.DynamicPseudoType),
},
{
Name: "keys",
Type: cty.List(cty.DynamicPseudoType),
},
{
Name: "searchset",
Type: cty.List(cty.DynamicPseudoType),
},
},
Type: func(args []cty.Value) (cty.Type, error) {
ty, _ := convert.UnifyUnsafe([]cty.Type{args[1].Type(), args[2].Type()})
if ty == cty.NilType {
return cty.NilType, errors.New("keys and searchset must be of the same type")
}
// the return type is based on args[0] (values)
return args[0].Type(), nil
},
RefineResult: refineNotNull,
Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) {
if !args[0].IsKnown() {
return cty.UnknownVal(cty.List(retType.ElementType())), nil
}
if args[0].LengthInt() != args[1].LengthInt() {
return cty.ListValEmpty(retType.ElementType()), errors.New("length of keys and values should be equal")
}
output := make([]cty.Value, 0)
values := args[0]
View on GitHub (pinned to c9def3e214)
Solutions
- Normalize both to the same element type: matchkeys(vals, keys, [for s in searchset : tostring(s)]).
- Construct keys and searchset from the same typed list literal.
- Use tolist() on both sides to ensure list-of-uniform-element types.
Example fix
# before
locals { r = matchkeys(var.values, var.keys, [var.want_id]) } # keys=str, want_id=num
# after
locals { r = matchkeys(var.values, var.keys, [tostring(var.want_id)]) } Defensive patterns
Strategy: type-guard
Validate before calling
# unify keys and searchset element types before matchkeys
locals {
search = [for s in var.searchset : tostring(s)]
r = matchkeys(var.values, var.keys, local.search)
} Type guard
locals {
keys_t = [for k in var.keys : tostring(k)]
search_t = [for s in var.searchset : tostring(s)]
r = matchkeys(var.values, local.keys_t, local.search_t)
} Try / catch
locals { r = try(matchkeys(var.values, var.keys, var.searchset), []) } Prevention
- Build keys and searchset from the same typed source.
- Use tolist() with explicit element conversions on both sides.
- Type variables strictly (list(string)) so coercion is deterministic.
When it happens
Trigger: matchkeys(vals, ["a","b"], [1]) (keys are strings, searchset numbers), or passing a list of one type and a set/tuple of incompatible element types.
Common situations: Building searchset from a different source whose element type differs; mixing string and number identifiers; a tuple vs list mismatch.
Related errors
- argument must be a string, a collection type, or a structura
- all arguments must have the same type
- argument must be a list or tuple
- length of keys and values should be equal
- input must be a map of lists of strings
AI-assisted analysis of hashicorp/terraform@c9def3e214 (2026-08-07).
Data as JSON: /api/errors/c2ee41ee8fd074a1.
Report an issue: GitHub.