hashicorp/terraform · error
lookup failed to find key %s
Error message
lookup failed to find key %s
What it means
Returned by the lookup built-in's Impl (LookupFunc, internal/lang/funcs/collection.go:326) when the requested key is absent from the map/object and no default value (third argument) was supplied. After unmarking and confirming both map and key are known, the function checks HasAttribute (objects) / HasIndex (maps); on miss with no default set it returns cty.UnknownVal(DynamicPseudoType) plus this error, with the key redacted if it carries sensitive marks.
Source
Thrown at internal/lang/funcs/collection.go:326
lookupKey := keyVal.AsString()
if mapVar.Type().IsObjectType() {
if mapVar.Type().HasAttribute(lookupKey) {
return mapVar.GetAttr(lookupKey).WithMarks(markses...), nil
}
} else if mapVar.HasIndex(cty.StringVal(lookupKey)) == cty.True {
return mapVar.Index(cty.StringVal(lookupKey)).WithMarks(markses...), nil
}
if defaultValueSet {
defaultVal, err = convert.Convert(defaultVal, retType)
if err != nil {
return cty.NilVal, err
}
return defaultVal.WithMarks(markses...), nil
}
return cty.UnknownVal(cty.DynamicPseudoType), fmt.Errorf(
"lookup failed to find key %s", redactIfSensitive(lookupKey, keyMarks))
},
})
// MatchkeysFunc constructs a function that constructs a new list by taking a
// subset of elements from one list whose indexes match the corresponding
// indexes of values in another list.
var MatchkeysFunc = function.New(&function.Spec{
Params: []function.Parameter{
{
Name: "values",
Type: cty.List(cty.DynamicPseudoType),
},
{
Name: "keys",
Type: cty.List(cty.DynamicPseudoType),
},
{View on GitHub (pinned to c9def3e214)
Solutions
- Supply a default: lookup(var.some_map, "missing_key", "fallback").
- Use try() to fall back gracefully: try(var.some_map.missing_key, "fallback").
- Verify the key exists with contains(keys(var.some_map), "missing_key") before lookup.
- Populate the map upstream so the expected key is always present.
Example fix
# before (HCL) v = lookup(var.tags, "env") # tags has no "env" -> lookup failed to find key "env" # after v = lookup(var.tags, "env", "default") # or v = try(var.tags.env, "default") # or guard: v = contains(keys(var.tags), "env") ? lookup(var.tags, "env") : "default
Defensive patterns
Strategy: fallback
Validate before calling
# (HCL) check existence before lookup
locals {
has_key = contains(keys(var.tags), "env")
v = local.has_key ? lookup(var.tags, "env") : "default"
} Type guard
# (HCL) type-ish guard using contains
locals {
key_present = contains(keys(var.tags), "env")
} Try / catch
# (HCL) always supply a default, or use try() value = lookup(var.tags, "env", "default") # or value = try(var.tags.env, "default")
Prevention
- Always pass a default to lookup for optional keys.
- Prefer try() for graceful attribute access on maps/objects.
- Use contains(keys(...), k) to check existence first.
- Populate maps upstream so expected keys always exist.
When it happens
Trigger: Calling lookup(var.some_map, "missing_key") where 'missing_key' is not present and no third default argument is given; both map and key are fully known so lookup falls through to the not-found path.
Common situations: Referencing a tag/label key that doesn't exist in the map, environment-specific maps missing a key in some workspaces, typo'd keys, or assuming a key exists when the source only populates it conditionally.
Related errors
- lookup() takes two or three arguments, got %d
- invalid CIDR expression: %s
- IPv6 addresses cannot have a netmask: %s
- Unknown validation type: %#v
- empty state name
AI-assisted analysis of hashicorp/terraform@c9def3e214 (2026-08-07).
Data as JSON: /api/errors/6cd297cf2ecf08a7.
Report an issue: GitHub.