HTTP 500 Internal Server Error - Troubleshooting#
This guide documents potential causes and recovery steps for the HTTP 500 Internal Server Error in the California Accountability Panel (CAP) application, in the Docker deployment described in Deploying on AWS.
Common Causes#
1. Database connection failures#
The most common cause of an HTTP 500 is the backend being unable to reach PostgreSQL.
Missing or wrong password:
DATABASE_URLis built incompose.yamlfromPOSTGRES_USERandPOSTGRES_PASSWORDin.env, whichdeploy.shwrites from SSM Parameter Store. If the parameter was rotated butdeploy.shhas not been re-run, the backend still holds the old value.The database container is not healthy:
docker compose psshows its health. Thebackendservice waits onservice_healthy, so a backend that started at all means the database was up at the time — it may have gone away since.The volume filled up: PostgreSQL refuses writes when the disk is full, which surfaces as 500s on anything that writes. Check with
df -h; an import that was interrupted mid-way is the usual reason.
2. Import failures#
S3 permissions: The instance role must allow
s3:GetObjecton theresources/prefix ands3:ListBucketon the bucket. A missing permission surfaces as anAccessDeniedfromboto3in the import output, not as a 500 — but it leaves the database empty, and endpoints querying empty reference tables can fail.PostgreSQL advisory locks: The importer uses
pg_try_advisory_lockto prevent concurrent imports. A lock held by a container that was killed is released when its session ends; if an import refuses to start, confirm no otherdocker compose runis still going.
3. Database schema mismatches#
If the schema does not match the SQLModel definitions in the code, queries fail. Errors naming a missing relation, such
as relation "academicindicator" does not exist, mean migrations have not been applied:
docker compose run --rm backend alembic upgrade head
4. Sentry integration#
If SENTRY_DSN is configured, errors are reported to Sentry. Check the dashboard for the TraceID to see the full
stack trace and the exact exception. A misconfigured or unreachable Sentry does not itself cause a 500.
Diagnostic Steps#
Read the logs:
docker compose logs -n 200 backend docker compose logs -n 50 db
Check the health endpoint. The application exposes
/api/v1/utils/health-check/. If it returnstruebut other endpoints fail, the problem is a query or the data, not startup.Open a shell against the database:
docker compose exec db psql -U blocks -c "\dt"
Re-run the deploy, which rewrites
.envfrom Parameter Store, applies migrations and restarts:./deploy.sh
Recovery#
Restart the stack:
docker compose up -d --force-recreate backend.Reload the data: the database is reproducible from S3 and the state’s web server. See Importing Research Files.
Restore: a daily EBS snapshot and a weekly
pg_dumpin S3 are described in Deploying on AWS.