Troubleshooting
Local development problems, roughly in the order new developers hit them. For production incidents see Runbooks.
Install and build
pnpm install produces lockfile changes I did not make
You are on the wrong pnpm version. The repo pins pnpm@9.0.0:
corepack enable
corepack prepare pnpm@9.0.0 --activate
pnpm --version # must print 9.0.0
git checkout pnpm-lock.yaml
pnpm installCannot find module '@playpals/db'
The shared packages have not been built. Services import from dist/, not source:
pnpm buildIf it persists, the Prisma client is missing:
cd packages/database && pnpm db:generate && pnpm buildTypeScript cannot find Prisma model types
packages/database/generated/ is git-ignored and produced by prisma generate. A fresh clone has no types until you generate them. Same fix as above.
Nuclear option
rm -rf node_modules apps/*/node_modules packages/*/node_modules
rm -rf .turbo apps/*/.turbo packages/*/.turbo
pnpm install
cd packages/database && pnpm db:generate && cd ../..
pnpm buildDatabase
Can't reach database server at localhost:5432
docker compose ps # is playpals-db running?
docker compose up -d db
docker compose logs db --tail 50Postgres takes a few seconds to initialise on first start. If something else on your machine already owns 5432 (a Homebrew Postgres, for instance), either stop it or remap the port in docker-compose.yaml.
Migration fails with a checksum or drift error
Someone edited an already-applied migration, or your local database is out of sync. Locally the fix is to reset:
docker compose down -v
docker compose up -d db redis
cd packages/database && pnpm db:migrate && pnpm db:seeddocker compose down -v deletes the volume and therefore all local data. Never run the equivalent against a shared environment.
The schema in my database does not match schema.prisma
cd packages/database && pnpm exec prisma migrate statusRedis and background jobs
NOAUTH Authentication required
The local Redis runs with --requirepass playpalz. Your connection string must carry the password:
REDIS_URL="redis://:playpalz@localhost:6379"This is the single most common local misconfiguration. Its symptom is not an obvious error in the UI — media uploads succeed but never produce thumbnails, and realtime events silently do not arrive.
Uploaded images never get thumbnails
The pipeline is: API writes the original to object storage → API enqueues a job → ogun processes it. Check each link:
# 1. Is the worker running?
pnpm --filter @playpals/ogun dev
# 2. Are jobs reaching the queue?
docker exec -it playpals-redis redis-cli -a playpalz KEYS 'bull:media-processing:*'
# 3. Are they failing?
docker exec -it playpals-redis redis-cli -a playpalz LRANGE 'bull:media-processing:failed' 0 -1ogun needs valid SPACES_* credentials to read the original and write variants. Without them it will pick up jobs and fail every one. See Media Pipeline.
Video posts stay in processing forever
Video goes to Mux, and the media record is only completed when Mux calls the webhook at POST /api/v1/webhooks/mux. Locally that callback cannot reach your laptop unless you tunnel it:
ngrok http 4000
# then point the Mux webhook at https://<id>.ngrok.io/api/v1/webhooks/muxRealtime
The socket connects and immediately disconnects
esu verifies the JWT the API issued, so both services must share the same JWT_SECRET. Compare apps/api/.env and apps/esu/.env. A mismatch presents as an instant disconnect with an auth error in the esu log.
Joining a DM or room is rejected with AUTHZ_DENIED
esu does not query the database for authorization. It calls back into the API (GET /api/v1/dm/:conversationId/authz and /room/:roomId/authz) using API_BASE_URL. If that points at the wrong port, every join is denied.
The default in apps/esu/.env.example is http://localhost:3000/api/v1, but the API's own .env.example sets PORT=4000. Set API_BASE_URL=http://localhost:4000/api/v1 to match.
Messages send but nobody receives them
The API fans out realtime events by calling esu's interservice admin endpoint. Check that the API's REALTIME_SERVICE_URL (http://localhost:4010/admin) and REALTIME_ADMIN_TOKEN match what esu expects in its own REALTIME_ADMIN_TOKEN.
Mobile
[Config] Missing env var: EXPO_PUBLIC_API_URL
Create apps/mobile/.env with EXPO_PUBLIC_API_URL and EXPO_PUBLIC_REALTIME_URL. See Local Setup.
Every API call 404s
EXPO_PUBLIC_API_URL must include the /api/v1 suffix — it is used verbatim as the axios baseURL.
The app cannot reach the API from a physical device
localhost on a phone means the phone. Use your machine's LAN IP and allow inbound connections on ports 4000 and 4010.
Metro serves stale code, or a module suddenly cannot be resolved
pnpm --filter @playpals/mobile start -- --clearIf that does not fix it, remove apps/mobile/.expo and restart.
The app crashes on launch after I installed a dependency
Native modules and config plugins are compiled into the development build. Installing them does not change the binary already on your simulator. Produce a new development build — see Builds & Releases.
Expo Go will not open the app
It cannot. The app depends on native modules (LiveKit / WebRTC, notifications, Bugsnag) that Expo Go does not include. Use the development client.
Ports already in use
| Port | Service |
|---|---|
| 3000 | web (Next.js) |
| 4000 | api |
| 4005 | anansi |
| 4010 | esu |
| 5173 | docs |
| 5432 | Postgres |
| 6379 | Redis |
| 7880–7882 | LiveKit |
lsof -i :4000
kill -9 <pid>Still stuck
- Read the service's
.env.example— the answer is usually a missing variable. - Check the service's config module (
src/configs/index.ts) to see what it actually reads and what it silently defaults to. - Turn up logging: backend services use pino, and
esulogs every inbound and outbound socket event whenSOCKET_EVENT_LOGGING=true.
