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

  1. Normalize both to the same element type: matchkeys(vals, keys, [for s in searchset : tostring(s)]).
  2. Construct keys and searchset from the same typed list literal.
  3. 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

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


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