{"record":{"id":"02785d499d6ada09","repo":"hashicorp/terraform","slug":"length-of-keys-and-values-should-be-equal","errorCode":null,"errorMessage":"length of keys and values should be equal","messagePattern":"length of keys and values should be equal","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/lang/funcs/collection.go","lineNumber":365,"sourceCode":"\t\t},\n\t},\n\tType: func(args []cty.Value) (cty.Type, error) {\n\t\tty, _ := convert.UnifyUnsafe([]cty.Type{args[1].Type(), args[2].Type()})\n\t\tif ty == cty.NilType {\n\t\t\treturn cty.NilType, errors.New(\"keys and searchset must be of the same type\")\n\t\t}\n\n\t\t// the return type is based on args[0] (values)\n\t\treturn args[0].Type(), nil\n\t},\n\tRefineResult: refineNotNull,\n\tImpl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) {\n\t\tif !args[0].IsKnown() {\n\t\t\treturn cty.UnknownVal(cty.List(retType.ElementType())), nil\n\t\t}\n\n\t\tif args[0].LengthInt() != args[1].LengthInt() {\n\t\t\treturn cty.ListValEmpty(retType.ElementType()), errors.New(\"length of keys and values should be equal\")\n\t\t}\n\n\t\toutput := make([]cty.Value, 0)\n\t\tvalues := args[0]\n\n\t\t// Keys and searchset must be the same type.\n\t\t// We can skip error checking here because we've already verified that\n\t\t// they can be unified in the Type function\n\t\tty, _ := convert.UnifyUnsafe([]cty.Type{args[1].Type(), args[2].Type()})\n\t\tkeys, _ := convert.Convert(args[1], ty)\n\t\tsearchset, _ := convert.Convert(args[2], ty)\n\n\t\t// if searchset is empty, return an empty list.\n\t\tif searchset.LengthInt() == 0 {\n\t\t\treturn cty.ListValEmpty(retType.ElementType()), nil\n\t\t}\n\n\t\tif !values.IsWhollyKnown() || !keys.IsWhollyKnown() {","sourceCodeStart":347,"sourceCodeEnd":383,"githubUrl":"https://github.com/hashicorp/terraform/blob/c9def3e214014c1188faabfc4a5bde5095139765/internal/lang/funcs/collection.go#L347-L383","documentation":"Thrown by MatchkeysFunc.Impl when len(values) != len(keys). matchkeys pairs values[i] with keys[i] by index, so the two lists must be the same length; a mismatch is a logic error.","triggerScenarios":"matchkeys(values, keys, searchset) where values and keys were built from different sources or filtered differently, producing unequal lengths.","commonSituations":"Two parallel lists that got out of sync; one list filtered while the other wasn't; copy-paste using the wrong variable.","solutions":["Build values and keys together from a single source with a for expression so they stay aligned.","Add a precondition/guard: assert length(values) == length(keys).","Re-derive the shorter list from the same iteration as the longer one."],"exampleFix":"# before\nlocals { m = matchkeys(var.names, var.ids, var.search_ids) }   # lengths differ\n# after: derive both from one source\nlocals {\n  pairs = [for x in var.items : { name = x.name, id = x.id }]\n  m     = matchkeys([for p in local.pairs : p.name], [for p in local.pairs : p.id], var.search_ids)\n}","handlingStrategy":"validation","validationCode":"# assert equal lengths before matchkeys\nlocals {\n  ok = length(var.values) == length(var.keys)\n  r  = local.ok ? matchkeys(var.values, var.keys, var.searchset) : []\n}\ncheck \"align\" {\n  assert {\n    condition     = length(var.values) == length(var.keys)\n    error_message = \"values and keys lists must have equal length\"\n  }\n}","typeGuard":null,"tryCatchPattern":"locals { r = try(matchkeys(var.values, var.keys, var.searchset), []) }","preventionTips":["Derive parallel lists from one for expression so they cannot drift.","Add check/precondition blocks asserting length parity.","Avoid independently filtering two lists that must stay aligned."],"tags":["hcl","function","matchkeys","validation"],"analyzedSha":"c9def3e214014c1188faabfc4a5bde5095139765","analyzedAt":"2026-08-07T15:39:49.278Z","schemaVersion":2},"datasetVersion":"2026-08-07T20:17:04.800Z"}