Terraform: Empty set doesn't work with dynamic for_each

Created on 28 Jan 2020  ยท  6Comments  ยท  Source: hashicorp/terraform

Terraform Version

Terraform v0.12.20
+ provider.azuread v0.7.0
+ provider.azurerm v1.41.0
+ provider.kubernetes v1.10.0
+ provider.null v2.1.2

Terraform Configuration Files

resource "aws_api_gateway_usage_plan" "these" {                                                               
  for_each = var.apig_plans                                                                                   

  name = "${local.namespace}-${each.key}-plan"                                                                

  api_stages {                                                                                                
    api_id = aws_api_gateway_rest_api.rest_api[0].id                                                          
    stage  = aws_api_gateway_rest_api.rest_api[0].name                                                        
  }                                                                                                           

  dynamic "quota_settings" {                                                                                  
    for_each = [for v in [each.value["quota"]] : v if v != {}]                                                

    content {                                                                                                 
      limit  = quota_settings.value["limit"]                                                                  
      offset = quota_settings.value["offset"]                                                                 
      period = quota_settings.value["period"]                                                                 
    }                                                                                                         
  }                                                                                                           

  dynamic "throttle_settings" {                                                                               
    for_each = [for v in [each.value["throttle"]] : v if v != {}]                                             

    content {                                                                                                 
      burst_limit = throttle_settings.value["burst_limit"]                                                    
      rate_limit  = throttle_settings.value["rate_limit"]                                                     
    }                                                                                                         
  }                                                                                                           
}                                                                                                             

Debug Output

Crash Output

Expected Behavior


No error appears and no dynamic block are applied.

Actual Behavior

The empty list in for_each, still tries to execute content with an empty object:

  on .terraform/modules/zappa/zappa/api-keys.tf line 15, in resource "aws_api_gateway_usage_plan" "these":
  15:       limit  = quota_settings.value["limit"]
    |----------------
    | quota_settings.value is object with no attributes

The given key does not identify an element in this collection value.

Steps to Reproduce

Additional Context

References

Originally reported in a comment on another issue.

bug config v0.12 waiting-response

All 6 comments

@pselle @aarcro FYI

Yes, I'm seeing this issue as well

Hi @Bessonov! Sorry for this odd behavior and thanks for reporting it

Could you please share the definition of var.apig_plans? I'd ideally like to see both the variable block that is declaring it and the value you're assigning to it, because I suspect this is a type mismatch causing the != operator to return false e.g. because it's trying to compare a map value with an object value.

If my theory about the cause is correct, then I think the following should work as an alternative approach:

    for_each = [for v in [each.value["quota"]] : v if length(v) > 0]

The == and != operators require that the types of the two arguments match, because there's no implied type conversion for those operators as there is with most other operators, functions, etc. For that reason, comparing to {} would only work if the value being compared were of type object({}): the empty object type. If the value being compared is instead a _map_ then an explicit conversion would be needed to force the types to match, like map(v) == map({}), but when the goal is to test whether the value is empty I think it'd read more clearly to use length(v) == 0 or length(v) > 0 to explicitly capture that intent.

@ktham can you provide an example?

@apparentlymart sorry, in meantime I've changed my configuration.

I am going to close this issue due to inactivity.

If there is still a question, I recommend the the community forum, where there are far more people available to help. If there is a bug or you would like to make a feature request, please open a new issue and fill out the template.
Thanks!

I'm going to lock this issue because it has been closed for _30 days_ โณ. This helps our maintainers find and focus on the active issues.

If you have found a problem that seems similar to this, please open a new issue and complete the issue template so we can capture all the details necessary to investigate further.

Was this page helpful?
0 / 5 - 0 ratings