Terraform Error: 'moved' block invalid reference (both endpoints exist)
Fix Terraform 'moved' block errors like 'Unable to move ... both refer to existing objects' and 'Invalid moved block address': point from an old, gone address to a new one.
- #terraform
- #iac
- #troubleshooting
- #errors
Fixing errors like this? Get 500 free DevOps AI prompts
500 copy-paste AI prompts for the stack you actually run — one PDF, free.
Exact Error Message
╷
│ Error: Unable to move resource instance
│
│ with aws_instance.web,
│ on moved.tf line 1:
│ 1: moved {
│
│ Both aws_instance.app and aws_instance.web refer to existing objects in
│ the configuration, so Terraform cannot move one to the other.
╵
Other variants from the same block:
│ Error: Invalid "moved" block
│
│ The "from" and "to" addresses must be different, but both refer to
│ aws_instance.web.
│ Error: Ambiguous move statements
│
│ A chain of move statements leads to aws_instance.web, but that address
│ appears as the "to" of more than one move.
What It Means
A moved block tells Terraform that a resource previously tracked at one address (from) should now be tracked at another (to), so state follows a rename or refactor without a destroy/create. The rule is that the from address must no longer exist in configuration, and the to address must be the new, declared resource.
The most common error appears when both addresses still have resource blocks in your config. Terraform will not silently merge two live resources, so it refuses the move. Other variants fire when from and to are identical, or when multiple moved blocks converge on the same destination.
Common Causes
- You added a
movedblock but forgot to delete the oldresource "..."block, so both endpoints still exist. fromandtoare the same address (copy-paste, or an incomplete edit).- Two
movedblocks both target the sametoaddress, creating an ambiguous chain. - The
toaddress does not match any declared resource (typo, wrong index, wrong module path). - Moving into a
for_each/countinstance with the wrong key/index syntax ([0]vs["a"]). - A module-boundary move where the
module.prefix is missing or wrong.
Diagnostic Commands
List what actually exists in state so you can see which address is real:
terraform state list
Show the concrete address you intend to move away from:
terraform state show aws_instance.app
Run a plan — moved blocks are resolved during plan, and the output shows moves as # ... has moved to ...:
terraform plan
Validate to catch malformed addresses before planning:
terraform validate
Step-by-Step Resolution
-
Decide the true old and new addresses. The
fromshould be the address that no longer has aresourceblock; thetoshould be the one that does. -
Delete the old resource block. Keep only the new resource plus the
movedblock:
# old block removed entirely — do NOT leave it in the file
resource "aws_instance" "web" {
ami = "ami-0abcd1234ef567890"
instance_type = "t3.micro"
}
moved {
from = aws_instance.app
to = aws_instance.web
}
-
Make sure
fromandtodiffer. If they are identical, the move is a no-op and must be removed or corrected. -
For instances under
count/for_each, use exact index/key syntax:
moved {
from = aws_instance.web
to = aws_instance.web["primary"]
}
- For a move across a module boundary, include the full
module.path on both sides:
moved {
from = aws_s3_bucket.logs
to = module.logging.aws_s3_bucket.logs
}
- Resolve ambiguous chains: ensure each
toaddress is targeted by only onemovedblock. Then plan and confirm the move shows as a state move, not a destroy/create:
terraform plan
# aws_instance.app has moved to aws_instance.web
- Once the move has been applied and state is updated, you may delete the
movedblock in a later change.
Prevention
- When renaming a resource, delete the old block in the same commit as you add the
movedblock. - Keep
from(gone from config) andto(declared in config) clearly distinct; never point a move at itself. - Use exact
for_eachkeys andcountindexes in move addresses. - Include the full
module.path when moving resources into or out of modules. - Run
terraform planafter any refactor to confirm moves resolve as state moves rather than replacements.
Related Errors
Resource instance managed by newer provider version— unrelated state/version mismatch, not a move.removed block ... still in configuration— theremovedblock sibling error when a resource is both removed and declared.Invalid resource instance key— wrongfor_each/countkey inside a move address.Reference to undeclared resource— thetoaddress names a resource that does not exist.
Frequently Asked Questions
Why does Terraform say both addresses exist? You left the old resource block in the config alongside the new one. A moved block requires the from address to be gone from configuration — delete the old block.
Do I keep the moved block forever? No. Once the move has been applied and state reflects the new address, you can safely remove the moved block in a subsequent change.
How do I move a resource into a module? Use the full path on the to side, e.g. to = module.logging.aws_s3_bucket.logs, and remove the standalone resource from the root. A Terraform prompt can help you draft the exact addresses.
What causes “ambiguous move statements”? Two moved blocks pointing at the same to address, or a chain that converges. Ensure each destination is targeted by only one move. For more state-refactor fixes, see the Terraform guides.
Get 500 Battle-Tested DevOps AI Prompts — Free
500 battle-tested, copy-paste AI prompts engineered by a senior systems engineer — every one with fill-in placeholders and safety/back-out notes. Drop your email and it's yours.
- 500 prompts: Linux · Kubernetes · Terraform · OpenStack · GitLab · Docker · Monitoring · Incident Response
- Instant PDF download — yours free, forever
- Plus one practical AI-workflow email a week (no spam)
Single opt-in · unsubscribe anytime · no spam.