So I’m trying to follow what this poster is doing. The module I’m using is this.
My code works fine if I only have one type of record in the YAML file, if I try to mix a normal record along with an alias then the code blows up. I noticed in the other discussion, there was mention of using a splat. Correct me if I’m wrong but I believe the module I’m using takes this into consideration, it’s just the for loop I’m using may not satisfy the code within the module.
Error: Inconsistent conditional result types
on .terraform/modules/records/modules/records/main.tf line 15, in resource "aws_route53_record" "this":
15: for_each = var.create && (var.zone_id != null || var.zone_name != null) ? local.recordsets : tomap({})
|----------------
| local.recordsets is object with 2 attributes
The true result value has the wrong type: object is required.
Working YAML file
zone_id: Z12345678
records:
- name: route53-alias1.example.com
type: A
alias:
name: abc.com
zone_id: Z12345678
- name: route53-alias.example.com
type: A
alias:
name: alias.elb.amazon.com
zone_id: Z12345678
Non-working YAML file
zone_id: Z12345678
records:
- name: route53-alias1.example.com
type: A
records:
- 192.168.0.1
- name: route53-alias.example.com
type: A
alias:
name: alias.elb.amazon.com
zone_id: Z12345678
main.tf
locals {
zone_data_raw = yamldecode(file("${path.module}//zone_data.yaml"))
zone_data = {
zone_id = local.zone_data_raw.zone_id
records = [for r in local.zone_data_raw.records : {
name = r.name
type = r.type
ttl = lookup(r, "ttl", null)
alias = lookup(r, "alias", {})
records = lookup(r, "records", null)
}]
}
}
module "records" {
source = "terraform-aws-modules/route53/aws//modules/records"
zone_id = local.zone_data_raw.zone_id
private_zone = true
records = local.zone_data.records
}
After days of staring at the code and Googling everywhere, I figured out my issue. The module I’m using turns the records into a map with the tomap
function. I used code from another post I found on here, but then I realized I didn’t need the for loop within locals
. Once I removed it, everything works as expected.
Updated code that works:
locals {
zone_data_raw = yamldecode(file("${path.module}//zone_data.yaml"))
}
module "records" {
source = "terraform-aws-modules/route53/aws//modules/records"
zone_id = local.zone_data_raw.zone_id
private_zone = true
records = local.zone_data_raw.records
}
Hi @luckytaxi,
I’m not sure I followed exactly what was going on in your original problem or in your solution, because the error message here was from a nested module whose source code you didn’t include, but in case it’s helpful I wanted to share a tip for writing conditional for_each
in a way that doesn’t run into this sort of type mismatch error:
for_each = {
for k, v in local.recordsets : k => v
if var.create && (var.zone_id != null || var.zone_name != null)
}
The above uses a for
expression with an if
clause. Although typically an if
clause will include references to the iteration symbols (k
and v
in this case), that’s not actually required and so we can also use an if
clause in this sort of situation where we either want to take all elements of local.recordsets
or no elements at all, because the if
clause can filter them all out and thus leave an empty mapping.
Doing this with a conditional expression ... ? ... : ...
is trickier because you need to make sure that the true and false outcomes both have compatible types, which I think was what your original error message was reporting: local.recordsets
has an object type while tomap({})
has a map type, and so Terraform can’t determine a single type for the conditional expression to return. The for
expression approach avoids that problem because both outcomes are derived from the same source collection (local.recordsets
) and so Terraform can automatically infer the result type in both situations by deriving it from that source value’s type.
1 Like