Summary
When a data block has for_each that evaluates to an empty collection, the resulting namespace (data.<type>.<name>) is never registered in the evaluation context. Any downstream reference (e.g. for_each = data.<type>.<name> on another data block or a transform) throws an "unknown reference" error instead of degrading to an empty iteration.
This forces every consumer of a for_each-driven data namespace to wrap their reference in try(data.X.Y, {}), which is ergonomically poor and easy to forget.
Reproducer
# .mptf.hcl
data "module" "for_order" {}
# When the tf-dir has no `module "..." {}` calls, this evaluates 0 times.
data "module_source" "for_order" {
for_each = data.module.for_order.result
source = each.value.source
}
transform "reorder_attributes" "module_full" {
for_each = data.module_source.for_order # ❌ data.module_source.for_order unknown
target_block_address = each.value.module_address
...
}
Running mapotf transform against a tf-dir with zero modules errors with unknown reference: data.module_source.for_order.
Current workaround
Wrap the consumer with try():
transform "reorder_attributes" "module_full" {
for_each = try(data.module_source.for_order, {})
...
}
The Azure AVM governance pipeline ships this workaround in mapotf-configs/order_module_attrs.mptf.hcl at https://github.com/Azure/avm-terraform-governance/blob/main/mapotf-configs/order_module_attrs.mptf.hcl with a comment block explaining the quirk. Cost is roughly nil at runtime but it's a foot-gun for anyone authoring new for_each-driven chains.
Suggested fix
In the data-block plan loop, when for_each is non-null but the evaluated collection is empty:
- Still register the
data.<type>.<name> namespace in the eval context.
- Bind it to an empty
cty.ObjectVal{} (or equivalent empty collection matching the block's value type).
This mirrors Terraform's own behaviour where for_each = [] on a resource produces an empty map under <resource_type>.<name> rather than an unknown reference.
Estimated cost: ~5 lines in the data-block iteration path, plus one test.
Impact
- Not a regression — pre-existing behaviour back to v0.1.0
- Low severity (documented
try() workaround is reliable)
- High ergonomic win (eliminates a documented foot-gun for
data.module / data.module_source chains)
Credit
Surfaced during real-world deployment in the Azure AVM Terraform governance pipeline alongside the v0.1.4 cleanup PR (Azure/avm-terraform-governance#472). Reported by the governance pipeline maintainer; verified in mapotf v0.1.4.
Summary
When a
datablock hasfor_eachthat evaluates to an empty collection, the resulting namespace (data.<type>.<name>) is never registered in the evaluation context. Any downstream reference (e.g.for_each = data.<type>.<name>on another data block or a transform) throws an "unknown reference" error instead of degrading to an empty iteration.This forces every consumer of a
for_each-driven data namespace to wrap their reference intry(data.X.Y, {}), which is ergonomically poor and easy to forget.Reproducer
Running
mapotf transformagainst a tf-dir with zero modules errors withunknown reference: data.module_source.for_order.Current workaround
Wrap the consumer with
try():The Azure AVM governance pipeline ships this workaround in
mapotf-configs/order_module_attrs.mptf.hclat https://github.com/Azure/avm-terraform-governance/blob/main/mapotf-configs/order_module_attrs.mptf.hcl with a comment block explaining the quirk. Cost is roughly nil at runtime but it's a foot-gun for anyone authoring newfor_each-driven chains.Suggested fix
In the data-block plan loop, when
for_eachis non-null but the evaluated collection is empty:data.<type>.<name>namespace in the eval context.cty.ObjectVal{}(or equivalent empty collection matching the block's value type).This mirrors Terraform's own behaviour where
for_each = []on a resource produces an empty map under<resource_type>.<name>rather than an unknown reference.Estimated cost: ~5 lines in the data-block iteration path, plus one test.
Impact
try()workaround is reliable)data.module/data.module_sourcechains)Credit
Surfaced during real-world deployment in the Azure AVM Terraform governance pipeline alongside the v0.1.4 cleanup PR (Azure/avm-terraform-governance#472). Reported by the governance pipeline maintainer; verified in mapotf v0.1.4.