Troubleshooting¶
Start with the exact symptom you can observe. Run commands from the repository root and keep the same Compose file and environment file as the topology you are diagnosing. The commands below use the development topology for problems specific to Getting Started.
Production-like initializer, gateway, and plugin failures¶
When the production-like topology does not serve Atlas, inspect services in
dependency order: postgres, initializer, backend, ingestor, then
frontend. The initializer applies migrations and collects static files; do
not start dependent services manually after it fails.
docker compose --env-file core/backend/.env ps
docker compose --env-file core/backend/.env logs postgres initializer backend ingestor frontend
For a plugin state reported by /healthz/plugins/ as degraded, inspect that
plugin's configuration and logs. Restarting only clears an in-process degraded
marker. It does not correct missing configuration or a composition contract.
An authentication provider is missing¶
Read /auth/browser/v1/config and /healthz/auth/providers/. An installed
package remains hidden and unusable until its id appears in the authoritative
auth.providers list and its runtime registers with the declared flow. Check
the manifest, selected owning plugin, lock, and generated settings. Regenerate
instead of editing runtime modules. If a redirect provider is default, open
/login?choose-provider=1 to inspect the other selected choices.
Signup or local login is rejected¶
Signup is closed by default. Enable it only through the local provider's
signup policy; exposing an allauth URL or local form does not override the
server check. Local login also requires atlas.auth.local to be selected.
Django admin password login has a separate disabled-by-default break-glass
policy and exact active-staff allowlist.
For an existing local account, distinguish an invalid credential from a selection or CSRF failure by its safe category and correlation id. Do not log the submitted username/password object or weaken generic invalid-credential responses.
OIDC redirect, discovery, or issuer fails¶
Confirm atlas.auth.oidc and its plugin are selected. Compare the discovery
URL with the metadata location and compare metadata issuer byte for byte
with expectedIssuer. Internal service names are not issuer aliases. Verify
the exact callback under auth.publicOrigin, client registration, allowed
algorithms, scopes, outbound destination policy, and trusted certificate.
A callback/state, nonce, PKCE, signature, audience, token-time, or UserInfo subject failure must stop before provisioning. Do not retry without the failed check or print the code, state, tokens, raw claims, or upstream body. See OIDC authentication.
Authentication reports CSRF or origin failure¶
Match auth.publicOrigin, the browser's complete scheme/host/port,
DJANGO_ALLOWED_HOSTS, and DJANGO_CSRF_TRUSTED_ORIGINS. Trust forwarded
headers only from configured proxy addresses. CORS does not replace CSRF.
Rejecting a foreign return URL is expected behavior.
A provider is unavailable but fallback should work¶
Inspect /healthz/auth/providers/. The endpoint reports every selected
provider independently and may return 503 while another provider is healthy.
Open the permanent provider chooser. If fallback is absent, confirm it is
selected; installation alone is insufficient. Keep timeouts and TLS verification in
place; do not turn a runtime outage into an insecure retry.
Login has an identity collision or provisioning failure¶
Use the correlation id and inspect exact provider, source, and subject through
manage_auth_identity inspect. Do not join accounts by matching username or
email. A link owned by another Principal requires an operator-reviewed exact
operation. For preprovisioned, the link must exist before login. For
restricted, recheck verified attribute provenance and current eligibility.
If login succeeds but ownership access is absent, inspect the Principal-to-Actor link. Manual Actor mode permits a session without an Actor; automatic mode can fail on a naming collision instead of claiming an unrelated Actor.
Group membership is missing, stale, or unexpectedly retained¶
Check the provider's snapshot status, explicit mapping, target Group, Actor link, grant source, expiry, link/source state, and current mode. Exact mode requires a complete snapshot and removes only that identity's omitted grants. Additive mode retains prior grants. A manual or other-provider grant keeps the effective membership after one source disappears. Classify legacy grants before enabling exact sync. See Group membership reconciliation.
Login works but a write is denied¶
Authentication does not grant authorization. Check the Actor link, effective
owner-Group membership, resource owner, Purge Grant when relevant, and the
selected PolicyEvaluator. Then check AccountAccess.read_only: it independently
denies writes even for a superuser or effective owner. Do not remap provider
groups or use break-glass to bypass a read-only restriction.
Logout appears incomplete¶
Atlas invalidates its local session first. The upstream browser session remains unless the provider declares and completes remote logout, so a later redirect may authenticate without another password prompt. Confirm that Atlas protected routes reject the old local session; test upstream logout separately.
Distribution composition fails¶
Run the resolver and validator against the manifest and lock before building.
Correct the named manifest entry or plugin contract, then resolve a new lock;
do not hand-edit generated modules or the lock; integrity comes from uv.lock and
package-lock.json. See Fix distribution
composition errors.
Diagram or feature rendering fails¶
Confirm backend health and the selected plugin state. Then preserve the failing browser request and inspect the corresponding backend and frontend logs. A missing feature tab usually means its plugin is not selected or is disabled; a plugin error needs its own configuration or runtime cause fixed. Do not reseed or reset a database to conceal a rendering failure. For C4 rendering dependencies and user-facing controls, follow the C4 feature guide; for an unavailable entity, restore a compatible kind provider before retrying.
Compose cannot read the development environment file¶
If Compose reports that core/backend/.env does not exist, check that the
example and destination paths are relative to the repository root:
If the example exists and the destination does not, create it:
Do not replace an existing customized file just to clear this symptom. If the
file exists but Compose rejects a value, compare its variable names with
.env.example and the environment variable
reference. Keep secrets out of
terminal output and issue reports.
The development stack does not build or start¶
- If the command cannot connect to the Docker daemon, start Docker and confirm
that
docker versionreports both a client and server before retrying. - If Docker reports that an address is already in use, free ports
5173,8000, and5432, or set the ComposeFRONTEND_PORT,BACKEND_PORT, orPOSTGRES_HOST_PORToverride incore/backend/.envbefore starting again. - If an image build fails, read the first failing build step. Fix the reported
dependency, network, or source error, then rerun the same
up --buildcommand; a later service health error is a separate symptom covered below. - If the backend reports a permission error writing to the mounted source tree
(on a Linux host whose user is not UID/GID
1000), rebuild the backend image with matching IDs:docker compose --env-file core/backend/.env -f docker-compose.dev.yml build --build-arg APP_UID=$(id -u) --build-arg APP_GID=$(id -g). The backend and ingestor images run as a non-rootappuser(UID/GID1000by default), not as root; see Containers run as a non-root user.
After correcting the cause, retry the documented command:
Confirming a topology is actually up¶
(Use http://localhost:8000/healthz/ and add -f docker-compose.dev.yml for the development
topology.) A failing curl means the gateway or backend is not serving yet. Check ps for a
service that is not healthy/running, then follow its logs.
For Getting Started, use the development Compose file consistently:
docker compose --env-file core/backend/.env -f docker-compose.dev.yml ps
docker compose --env-file core/backend/.env -f docker-compose.dev.yml logs postgres migrate backend frontend ingestor
Start with the first service that is exited (with a non-zero status) or
unhealthy. PostgreSQL must be healthy before the one-shot migrate service
can run, migrate must complete successfully before the backend and ingestor
start, and the backend must be healthy before the frontend starts. Correct
that earliest failure, rerun up --build, and repeat ps before continuing.
First start on either topology
On the production-like topology, the initializer service must finish migrations and
collectstatic before the backend, ingestor, and gateway will start serving; on the
development topology, the migrate service plays the same gating role (without
collectstatic). If nothing responds yet, check that service's logs first — the other
services are waiting on it and may not be failing independently.
The frontend can't reach the backend¶
In the development topology, the Vite dev server proxies /api, /_allauth, and /admin to the
backend. If those requests fail, confirm the backend container is healthy (see above)
before investigating the frontend configuration.
Database migrations do not complete¶
On a fresh or reset development database, the one-shot migrate service runs
before backend and ingestor start; if it fails, neither of them starts.
Confirm this is the failure by checking service state and the migrate
service's own logs:
docker compose --env-file core/backend/.env -f docker-compose.dev.yml ps
docker compose --env-file core/backend/.env -f docker-compose.dev.yml logs migrate
A connection-refused or name-resolution error means migrate could not reach
PostgreSQL; diagnose the postgres service and its logs first. If Django
names a specific migration, keep that error, correct the underlying cause, and
rerun up --build — Compose recreates and reruns the exited migrate
service.
If the topology is already running and you pulled new migrations, inspect the
plan without changing the database, then apply them directly against
backend:
docker compose --env-file core/backend/.env -f docker-compose.dev.yml exec backend python manage.py showmigrations
docker compose --env-file core/backend/.env -f docker-compose.dev.yml exec backend python manage.py migrate
Do not fake migration records or edit the database by hand. If Atlas explicitly classifies the migration as unsafe, use the next procedure instead.
Migration was rejected as unsafe¶
A migration touching a dropped column/table, or narrowing a field's nullability without a default, fails the safety check by design. The check protects a rolling upgrade breaking a still-running previous release. If the change genuinely is safe (e.g. reviewed maintenance-mode work), mark the specific operation with a required justification comment rather than working around the check.
The booking demo does not load¶
The demo command is successful only after it prints its final Seeded ...
summary. A missing-table error normally means migrations were not applied to
this development database; complete Database migrations do not
complete, then run the seed again.
For any other failure, preserve the command output and inspect the backend log:
The command flushes the target database before loading the demo. Retry it only when that database is disposable, using the exact development-topology command from Getting Started, and wait for the final summary before signing in.
The backend health check fails¶
If curl --fail http://localhost:8000/healthz/ reports connection refused,
confirm that the backend container is running and that BACKEND_PORT has not
changed the host port. If it returns an HTTP error, inspect the backend logs:
docker compose --env-file core/backend/.env -f docker-compose.dev.yml ps backend
docker compose --env-file core/backend/.env -f docker-compose.dev.yml logs backend
Return to Confirming a topology is actually up if the backend is unhealthy. Do not continue to browser diagnosis until the health request succeeds.
The seeded administrator cannot sign in¶
The admin / admin account exists only after seed_booking_demo --yes
finishes with its Seeded ... summary. If the account is rejected:
- Confirm that the seed command completed against the same development topology and database now serving the browser.
- Confirm that backend health succeeds.
- Open the frontend at the configured development origin (by default http://localhost:5173). Do not call the backend login endpoint on a different origin.
- Inspect the browser request and backend log. A refused
/apior/_allauthrequest is a frontend-to-backend symptom; an origin or CSRF rejection means the configured allowed/trusted origins do not match the URL in the browser.
Use The frontend can't reach the backend for proxy failures. Do not expose passwords, cookies, CSRF tokens, or secret settings in copied logs.
The seeded catalog is missing or does not render¶
If Booking & Reservations is absent, first confirm that the seed printed its final summary and that the Systems list is not filtered. A blank list after a successful seed usually means the browser and seed command are using different running projects or databases.
If the entity exists but its detail, Relations, or diagram view shows an error, check backend health and then inspect the backend and frontend logs:
Record the failing browser request and the first corresponding server error. Do not rerun the destructive seed merely to hide a rendering or API failure.
Starting over locally¶
Removes that topology's database and generated static data, not repository files. See Operations for the development-topology equivalent.