Error: Invalid reference: "must be followed by at least one attribute access" in dynamic blocks
Fixes Terraform's "Error: Invalid reference ... A reference to a resource type must be followed by at least one attribute access" when a bare resource type is used as a value (common in dynamic blocks). Use when validate fails on a dynamic block iterator or content. Reference a specific attribute or each.value; not for undeclared-resource typos.
TL;DR
You used a bare resource type (or a reserved word like module) where Terraform expected a full reference with an attribute. This bites most often in dynamic blocks when the iterator is named module or the content references the block label instead of the iterator. Rename the iterator and reference [iterator].value.[attr].
The error
Error: Invalid reference
A reference to a resource type must be followed by at least one attribute accessSteps to fix
- Open the flagged block. Check the
dynamicblock'siteratorargument: if it ismodule(or another reserved word), that is the bug.
- Expected: you find the reserved-word iterator.
- Rename it to something descriptive:
dynamic "origins" {
for_each = try(var.settings.origins, {})
iterator = origin
content {
name = origin.value.name
}
}- Expected: content references
origin.value, notmodule.value.
- If there is no dynamic block, find the bare type reference (
aws_instanceinstead ofaws_instance.web.id) and complete it.
- Expected: every reference ends in an attribute access.
- Run
terraform validate.
- Expected:
Success! The configuration is valid.
When to use this
validate/planfails withInvalid reference ... must be followed by at least one attribute access, especially insidedynamicblocks.
When NOT to use this
Reference to undeclared resourcemeans the name is wrong or missing.Unsupported attributemeans the attribute (not the reference shape) is wrong.
Compatibility
- Terraform 0.12+;
dynamicblocks and themodulereserved word behavior are stable across 1.x.
Root cause
module, var, local, each, and resource type names are reserved or structural. As an iterator name, module shadows the real module object, so module.value inside content parses as a malformed reference instead of the iterator. Terraform requires references to terminate in an attribute access, and the shadowed form never does.
Edge cases
selfinside provisioners has similar shadowing rules; keep iterator names descriptive and unique.for_eachdirectly on a resource witheach.key/each.valueis fine; the problem is only the iterator naming insidedynamic.- Linters (tflint) flag reserved-word iterators before Terraform does; run them in CI.
Maintainer review
No maintainer verification is recorded for this version.
This records the version a maintainer checked. It does not assert that the version is the latest upstream release.