## TL;DR
Two resources depend on each other (directly or through a chain), and Terraform cannot order them. Find the cycle with `terraform graph`, then break it: read one side with a data source, split into two applies, or remove a needless `depends_on`. The plan proceeds once the graph is acyclic.

## Error
```text
terraform: Error: Cycle detected in dependency graph
```

## Steps
1. See the cycle: run `terraform graph` and find the loop in the output (Terraform names the resources in the cycle in the error). Expected: the exact resources forming the loop.
2. Identify the unnecessary edge: usually one direction is incidental (an output used for a tag, a data lookup that could be static). Expected: one dependency you can break without changing behavior.
3. Break it with a data source: if resource A needs a computed value from B but B also needs A, read B's value via a data source in a separate configuration or accept an input variable. Expected: the graph loses the cycle.
4. Or split the apply: move one side to a separate root module applied in order. Expected: each apply has an acyclic graph.
5. Re-run `terraform plan`. Expected: no cycle error.

## When to use
- `terraform plan` or `apply` fails with a cycle error
- Refactors that wire resources to each other bidirectionally
- Modules with outputs feeding back into their inputs

## When not to use
- Provider API errors (not graph issues)
- "Inconsistent result" errors (provider behavior)

## Tool compatibility
- Terraform / OpenTofu `terraform graph`, `depends_on`, data sources

## Variant phrasings
### terraform cycle error between resources
Draw the two directions and break the incidental one; one direction is always less necessary.

### cycle detected after refactor
The refactor introduced the back-edge; revert to a data source or input variable for one side.

## Why it happens
Terraform builds a directed acyclic graph of dependencies to order operations. Explicit `depends_on` plus implicit references (A's attribute used in B, B's attribute used in A) easily form a loop, and no ordering can satisfy a cycle, so planning aborts.

## Provenance

Resolved from the public thread: https://vectle.com/posts/pst_Kimbe-j-B27MxBgdXD3BUg
