Troubleshooting¶
Every error atlantide raises has a name, and the name says which stage failed.
Run any command with --debug to get the full traceback and cause chain instead
of the one-line rendering.
The stage numbers below refer to the pipeline.
Config does not compile (stages 1–2)¶
LanguageError — the config uses a construct outside the Atlas-lang subset.
The message names the construct, the line, and the replacement:
error: construct 'While' is not allowed in Atlas-lang — Atlas-lang has no
`while` (halting must be provable); use a bounded `for`. (line 2, col 0)
See what config may not do for the full
list. import os fails the same way: imports are restricted to atlantide.*.
FuelExhaustedError — evaluation exceeded its step budget. Almost always a
runaway recursion or a loop over something far larger than intended. Recursion
is not rejected at parse time, so this is where it surfaces.
IRError — a value reached a resource field that cannot be canonicalized.
Config data must be plain JSON-shaped values.
RegistryError — an unknown or duplicate name, or a bad version. Two
resources sharing a logical name in one stack, a provider that is not installed,
or a component alias that was never added.
The graph is not a DAG (stage 4)¶
CycleError — resources depend on each other in a loop. The message names
the cycle. Usually two resources each reading a field from the other; break it
by passing a literal on one side, or by splitting the resource.
StackOutputCycleError — cross-stack output() references form a loop, for
example common:vpc_id -> dev:x -> common:vpc_id. Raised before lowering, so
the chain names the output keys rather than the resources.
The plan is refused (stage 7)¶
PreventDestroyError — a planned destroy hit a resource with
Lifecycle(prevent_destroy=True). Deliberate: --replace and destroy honour
it too. Remove the guard in config and re-plan if the destroy is intended.
PolicyViolationError — one or more mandatory policies failed, and the
apply is blocked. plan exits 1. Fix the resource, or lower the binding to
level=PolicyLevel.ADVISORY if it should warn rather than block. See
Policies.
PolicyConfigError — a policy binding passes arguments the policy cannot
use, e.g. enforce("require-tags", keys=3). The message names both.
Locking and concurrency (stage 8)¶
LockError — the lease could not be acquired: another run holds it. The run
never started, so nothing was written. Wait, or inspect with
atlantide state unlock.
LeaseLostError — the run did start, wrote to the provider, and then
found its lease taken by someone else. Nothing is rolled back: a
compensation is itself a state write, and a run that no longer holds the lock
must not make one. Run atlantide refresh to see what actually exists before
applying again.
FencedWriteError — the store refused a write because the recorded holder
is someone else. Distinct from LeaseLostError in who decided: a run whose
local clock still believes its lease is good can be wrong, a conditional write
against the recorded holder cannot. This is the last line between two concurrent
runs and a silently merged state.
PlanDriftError — the changeset about to run is not the one that was
approved. Apply re-diffs once it holds the lease — it must, or a resource
another run created in the meantime would be planned as a CREATE and built
twice — so the plan a human read and the plan about to execute can differ. The
message names what was added and what disappeared:
state changed between the plan you approved and the lock being taken, so the
changes are no longer the ones shown — now also: delete aws.S3Bucket:old.
Re-run to plan against current state.
Re-run. It is raised rather than reconciled because the gap between the two plans is exactly where an unreviewed destroy fits.
During apply¶
ProviderError — a provider CRUD call failed. Carries structured context:
which resource (node_id), which phase (op), which type (resource_type).
Under the default --on-failure rollback the nodes already completed are
undone; see When apply fails.
RollbackError — a compensation could not complete after a failed apply.
This is the case that needs attention: a compensation is a provider call
followed by a state write, so a partial one can leave state describing a
resource that is no longer there — and because the stored hash still matches
config, the next plan reports NOOP. Run atlantide refresh before
trusting the next plan. Raised alongside the original failure, never instead of
it.
InterruptedRunError — Ctrl-C. Not an infrastructure failure, so it exits
130 rather than 1 and drops the error: framing. Completed nodes are
compensated on the way out, where the run still held its lock.
State, secrets, artifacts, components¶
StateError — the state backend operation failed. With a remote backend,
atlantide state check verifies reachability and setup up front rather than
surfacing one failed API call at a time.
SecretsError — sealing or unsealing failed: unknown backend, wrong key, or
corrupt ciphertext. If plan shows every secret as rotated and none intact,
the keyfile is the wrong one — plan recognises that pattern and warns rather
than rendering a page of spurious updates. See
Secrets.
ArtifactError — a .atlas artifact is malformed, corrupted, or fails its
hash check. atlantide verify performs that check on its own.
ComponentError — fetching, vendoring or verifying a component failed:
a bad git source, a missing --subdir, or a vendored tree whose content hash no
longer matches atlantide.lock. atlantide component vendor rebuilds
.atlantis/ from the lock; component verify re-hashes it.
Things that are not errors¶
A plugin that failed to load. atlantide providers lists it and exits 1.
Config simply cannot find that provider's types, which otherwise presents as a
typo. --no-plugins ignores installed plugins entirely — useful for
reproducing a build or bisecting a plugin that has broken a run.
A plan that shows changes you did not make. The diff compares desired inputs
against recorded inputs, not against the live world. Something changed the
config or the state, not the cloud. To compare against reality, use
atlantide refresh.
A resource the provider could not find during refresh. It is reported but
kept, unless --prune is given. One failed read is not enough evidence to
discard the only record that a resource exists — discarding it means the next
apply builds a second one.