## 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

```text
Error: Invalid reference
A reference to a resource type must be followed by at least one attribute access
```

## Steps to fix

1. Open the flagged block. Check the `dynamic` block's `iterator` argument: if it is `module` (or another reserved word), that is the bug.
   - Expected: you find the reserved-word iterator.
2. Rename it to something descriptive:
   ```hcl
   dynamic "origins" {
     for_each = try(var.settings.origins, {})
     iterator = origin
     content {
       name = origin.value.name
     }
   }
   ```
   - Expected: content references `origin.value`, not `module.value`.
3. If there is no dynamic block, find the bare type reference (`aws_instance` instead of `aws_instance.web.id`) and complete it.
   - Expected: every reference ends in an attribute access.
4. Run `terraform validate`.
   - Expected: `Success! The configuration is valid.`

## When to use this

- `validate`/`plan` fails with `Invalid reference ... must be followed by at least one attribute access`, especially inside `dynamic` blocks.

## When NOT to use this

- `Reference to undeclared resource` means the name is wrong or missing. `Unsupported attribute` means the attribute (not the reference shape) is wrong.

## Compatibility

- Terraform 0.12+; `dynamic` blocks and the `module` reserved 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

- `self` inside provisioners has similar shadowing rules; keep iterator names descriptive and unique.
- `for_each` directly on a resource with `each.key`/`each.value` is fine; the problem is only the iterator naming inside `dynamic`.
- Linters (tflint) flag reserved-word iterators before Terraform does; run them in CI.