Rock and a Hard Place: lookup()

Error: Incorrect attribute value type

  on .terraform/modules/scry_integration/main.tf line 27, in resource "aws_apigatewayv2_route" "r":
  27:   authorization_scopes = lookup(each.value, "authorization_scopes", null)
    |----------------
    | each.value is map of string with 1 element

Inappropriate value for attribute "authorization_scopes": set of string
required.

OK fine, I’ll make the default an empty list.

Error: Invalid function argument

  on .terraform/modules/scry_integration/main.tf line 27, in resource "aws_apigatewayv2_route" "r":
  27:   authorization_scopes = lookup(each.value, "authorization_scopes", [])

Invalid value for "default" parameter: the default value must have the same
type as the map elements.

Noooo!!! So, what contortions do I have to do to make this work?

Hi @grimm26,

I’m not sure that the first error is caused by the type of that second argument, because the error seems to be talking about authorization_scopes's own type constraint. Specifically, the error message says that each.value is a map of string and therefore each.value["authorization_scopes"] would be a string, and that doesn’t meet the “set of string” type constraint.

I’m not sure what to suggest without seeing more context, but if you can make that expression produce something that can convert automatically to a set of string, such as a single-element list, I think null should then work just fine as a fallback.

so, each.key is a map. It has no key for authorization_scopes because I am testing defaults. The first error is indeed because aws_apigatewayv2_route.authorization_scopes expects a list of strings and I gave it a null. But when I set the default value for the lookup to return an empty list, then lookup complains. For that plan, each.key is a map that has only one key and its value is a string, so I assume that that’s what is making lookup think that all values of that map need to be strings.

That led me to have to define the variable feeding the for_each of that resource to be
type = list(
object(
{
authorization_scopes = list(string)
authorization_type = string
authorizer_id = string
route_key = string
}
)
)

Which means that the consumer always has to fill out all of the null or empty values because it is not possible to define an object type with optional pieces.