data block with for_each evaluating to empty collection does not register namespace, breaking downstream references
- Dominant language
- Go
- Stars
- 60
- Forks
- 19
- Avg merge
- 2h 2m
- Merged PRs (30d)
- 4
Description
## Summary
When a `data` block has `for_each` that evaluates to an empty collection, the resulting namespace (`data..`) is never registered in the evaluation context. Any downstream reference (e.g. `for_each = data..` 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
```hcl
# .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()`:
```hcl
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:
1. Still register the `data..` namespace in the eval context.
2. 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 `.` 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](https://github.com/Azure/avm-terraform-governance/pull/472)). Reported by the governance pipeline maintainer; verified in mapotf v0.1.4.
Contributor guide
No contributing guide indexed for this repository
Assessment
This issue has not been assessed yet.