Terraform Resource Address Parser

Break an address into its steps: the module path first, the resource last. Two things here are what actually break terraform state and -target commands, and neither produces a helpful error.

Paste below, or drop a file anywhere on this panel

Or drop a file anywhere on this panel. Nothing is uploaded: the analysis runs in this tab.

The answer appears here

Paste on the left and press Parse. Nothing leaves this tab.

Examples

Real input you can load into the tool above. Each one shows a different thing going wrong, because that is what the tool is for.

A for_each key inside a module

Two steps, a stable key, and brackets that need quoting on the command line

module.vpc.aws_subnet.private["eu-west-1a"]

An attribute on the end

Valid as an expression and rejected as an address, and the error names the resource

aws_instance.web.id

A count index

Positional, so removing an earlier element makes this address point somewhere else

aws_instance.web[0]

Common mistakes

These are the ones that fail silently. The config is accepted, nothing raises an error, and the consequence arrives later.

  1. Passing an address with an attribute on the end

    terraform state show aws_instance.web.id reports that no such resource is in state. The address is fine up to the attribute, so the error points at the wrong thing.

    Instead:Drop everything after the resource name. Keep the attribute only inside expressions.

  2. Not quoting an address that contains brackets

    zsh fails on the glob before Terraform runs; bash silently strips the double quotes and hands Terraform a different address.

    Instead:Always single-quote the whole address: terraform state rm 'module.a["k"]'.

  3. Reading a count index as a stable identity

    web[1] is the second element of a list, not a particular server. Removing web[0] renumbers everything, so the addresses now point at different objects.

    Instead:Use for_each keyed by something meaningful when the collection can change in the middle.

An address is not an expression, and your shell has opinions about brackets

Addresses look like the references you write in configuration and are a narrower thing. The two differences below are where the time goes.

An attribute is not part of the address

aws_instance.web.id is a valid expression and not a valid address. terraform state show and -target want the resource, so the trailing .id makes them report a resource that does not exist, which reads like a state problem rather than one extra component.

Brackets are shell metacharacters

terraform state rm module.a["k"] unquoted: zsh fails on the glob before Terraform starts, and bash strips the double quotes so Terraform receives an address that is not what you typed. Wrap the whole address in single quotes, every time, and the problem disappears.

A numeric key means count and is positional

aws_instance.web[0] is the first element of a count. Remove an earlier element and every later index shifts, so this address now names a different object and Terraform destroys and recreates the tail of the list. That is the reason to prefer for_each.

A string key means for_each and is stable

aws_subnet.private["eu-west-1a"] keeps its identity when other keys are added or removed. The key is part of the address, so choosing keys that mean something makes state readable years later.

A module address is valid for some commands and not others

-target and state list accept module.vpc and act on everything inside it. state show needs a single object and rejects it. Targeting a module is a bigger hammer than people expect, since it pulls in every resource the module declares.

A data source is in state and is not managed

data.aws_ami.ubuntu appears in state list, which inflates the count and confuses cleanup. It is re-read every plan, so removing it from state changes nothing, and destroy ignores it entirely.