Skip to content
open-ismsDocs

Search documentation

Find a page by title or topic

Troubleshooting

Symptoms, causes, and the commands that tell them apart.

Start with these three, in order. Between them they explain most of what goes wrong.

docker compose ps                        # is anything restarting
docker compose logs app | tail -50       # why
curl -s http://localhost:3026/api/health # does it reach the database

Startup#

SymptomCause
Bind for 0.0.0.0:3026 failed: port is already allocatedAnother program on the machine holds that port. Change APP_PORT, POSTGRES_PORT or MINIO_PORT in .env and start again. If you change MINIO_PORT, move AWS_S3_ENDPOINT to the same port: presigned upload URLs are signed for that exact address. The installer picks free ports by itself.
Environment validation failed: AUTH_SECRETUnder 32 characters, or unset.
Container restarts, logs stop after [migrate] connected to databaseA migration failed. Read the lines above the exit. The container refuses to serve on a half-applied schema, and your data is intact. Pin the previous version to get back up: Updating.
Migration waits, then gives upAnother container is migrating the same database, or a long-running query holds a lock. The migrator takes a Postgres advisory lock and waits MIGRATE_LOCK_WAIT, 300s by default.
no matching manifest for linux/...The architecture is neither x86-64 nor ARM64. Those are the two published.
Build killed at exit code 137Only reachable when building from source. Docker has under 4 GB. A normal install pulls the image and compiles nothing.

Login#

SymptomCause
Login redirects back to the sign-in page foreverAUTH_URL does not match the scheme users actually reach you on. This is the single most common self-host failure. Auth.js picks its cookie name from that URL's scheme, so the middleware is looking for a cookie the browser never received.
Sign-up says the code was sent, no email arrivesRESEND_API_KEY is unset, so nothing was sent. The code is in the log: docker compose logs app | grep "sign-in code". Configure a provider before inviting anyone else. See Email.
Registration succeeds but no code, and the domain is newSign-up checks domain age over RDAP as a throwaway-address signal. It fails open, so this is rarely the cause, but a very new domain is worth ruling out.

Content#

SymptomCause
Portal loads but there are no requirementsThe framework data did not load. From 0.2.9 the container does this itself at startup, so check the log for a [seed] line saying why. On older versions it was a manual step: Framework data.
Requirement counts look wrong after an updateThe framework migration in that release has not applied. Check docker compose logs app for [migrate lines and confirm the version at /api/health.

Evidence uploads#

SymptomCause
Upload fails in the browser with a CSP errorAWS_S3_ENDPOINT does not match the origin the browser is PUTting to. The policy is computed per request, so curl -sI https://your-url/ | grep -i content-security-policy shows exactly what it currently allows.
An evidence row appears but the file is not in the bucketThe browser's upload was refused and the server never learned. Presigning is offline, so nothing server-side notices a blocked PUT. Check the CSP row above first, then that the bucket exists.
Upload rejected, MinIO logs mention server-side encryptionMINIO_KMS_KEY is unset or is not 32 bytes of base64.
Upload works, deleting an evidence file failsAWS_S3_INTERNAL_ENDPOINT is wrong. Uploads never touch it; deletion is the first call the server actually makes.
Bind for 0.0.0.0:9000 failed: port is already allocatedSomething else on the box uses 9000. Set MINIO_PORT and match AWS_S3_ENDPOINT to it.

Certificates#

SymptomCause
TLS error instead of a page, right after enabling proxyDNS did not resolve to this server when Caddy ordered the certificate. Point the record, then docker compose restart proxy.
The app works but evidence uploads fail over HTTPSSTORAGE_DOMAIN has no certificate, or AWS_S3_ENDPOINT still says http://localhost:9000. Both names need to resolve here and both have to match.

Getting help#

Open an issue at github.com/NISD2/open-isms/issues. Include:

  • your compose.yaml and .env with every secret stripped,
  • docker compose logs app | tail -50,
  • what curl -s localhost:3026/api/health returns.

The version in that health response is the first thing anyone will ask for.