Misleading error message for an incorrect dynamic block iterator
Terraform Version
Terraform v1.6.2
on darwin_arm64
+ provider registry.terraform.io/cloudflare/cloudflare v4.8.0
Terraform Configuration Files
terraform {
required_version = ">= 1.5.0"
required_providers {
cloudflare = {
source = "cloudflare/cloudflare"
version = "~> 4.0"
}
}
}
data "cloudflare_zone" "example" {
name = "example.org"
}
locals {
example1_ip_ranges = [
"1.2.3.4/32",
"1.2.3.4/32",
]
example2_ip_ranges = [
"1.2.3.4/32",
"1.2.3.4/32",
]
}
resource "cloudflare_zone_lockdown" "example" {
zone_id = data.cloudflare_zone.example.zone_id
urls = ["https://*.example.org"]
dynamic "configurations" {
for_each = concat(local.example1_ip_ranges, local.example2_ip_ranges)
iterator = "client"
content {
target = "ip_range"
value = client.value
}
}
}
Debug Output
n/a
Expected Behavior
It should have told me that "client" was an invalid value for the iterator argument. As soon as I de-quoted it, everything works as expected.
Actual Behavior
╷
│ Error: Insufficient configurations blocks
│
│ on zonelockdown.tf line 13, in resource "cloudflare_zone_lockdown" "example":
│ 13: resource "cloudflare_zone_lockdown" "example" {
│
│ At least 1 "configurations" blocks are required.
╵
╷
│ Error: Unknown variable
│
│ on zonelockdown.tf line 19, in resource "cloudflare_zone_lockdown" "example":
│ 19: for_each = concat(local.example1_ip_ranges, local.example2_ip_ranges)
│
│ There is no variable named "local".
╵
╷
│ Error: Unknown variable
│
│ on zonelockdown.tf line 19, in resource "cloudflare_zone_lockdown" "example":
│ 19: for_each = concat(local.example1_ip_ranges, local.example2_ip_ranges)
│
│ There is no variable named "local".
Steps to Reproduce
terraform validate
Additional Context
No response
References
No response
Thanks for reporting this, @acdha!
Unfortunately the error message you included has a code snippet that doesn't match the source code you shared. I assume that's because you've modified whatever you actually tried in order to share it. So we can make sure that we are reproducing what you intended to report, can you share an example that reproduces the problem without needing any modifications first, and the error message you saw when you tried exactly that code?
Thanks again!
@apparentlymart I updated the example and response with a more carefully redacted version. Now it's a single file including the data lookup I was using and the provider versions.
Thanks, @acdha!
Using the configuration you shared I reproduced exactly the behavior you observed, without any modifications. (The fact that this is visible using terraform validate means that a functioning CloudFlare account isn't required to reproduce the problem.)
This bug actually seems to belong to the upstream HCL library rather than to Terraform itself, since that's where this idea of dynamic blocks is implemented. However, from reading the relevant HCL source code I've not yet completely determined why this occurs, so further debugging is needed here.
The relevant parts I've reviewed so far:
-
Interpreting the
iteratorargument as a "traversal" (a reference expression) and returning early with errors if that interpretation fails.Specifically, I would expect this to produce the detail message "A single static variable reference is required: only attribute access and indexing with constant keys. No calculations, function calls, template expressions, etc are allowed here.". (Relevant error handling)
-
The caller of
decodeSpecshould notice the returned error, append it to the growingdiagssequence, and then continue processing any otherdynamicblocks. There are no other blocks in this example, so iteration should end here.
I have a hunch that Terraform's way of using this HCL feature might be contributing. Terraform decodes resource blocks in two phases:
-
PartialContentto find the various "meta-arguments" that are handled by Terraform Core itself, such ascount,for_each,depends_on, etc. - Much later on,
Contentto collect up the rest of the content that's ultimately interpreted by the associated provider rather than by Terraform Core.
If I recall correctly, the "dynamic block" expansion happens just before the second evaluation, in which case the first evaluation would not be exercising this "dynamic block" code in HCL at all, and the expansion would instead be happening on the remnants of the original body that weren't consumed by PartialContent.
Therefore it isn't clear to me exactly why that two-step decoding process should cause a problem here, but it could potentially be.
I hope the above is a useful starting point for a future person who is working on debugging this further! For now, I'm going to add the labels to indicate that this is a confirmed bug that has not yet been explained, which means this issue is now at step 3 of the bug process.
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.