Troubleshooting
Common issues and how to resolve them.
Development
Health Check Returns db: "error"
The API can't reach PostgreSQL. Verify the database container is running:
docker compose -f infra/docker-compose.local.yml ps
If the container isn't running, start it:
docker compose -f infra/docker-compose.local.yml up -d
Prisma Client Import Errors
After schema changes, regenerate the Prisma client:
cd apps/api
npx prisma generate
Import PrismaClient from the generated path, not @prisma/client:
import { PrismaClient } from '../generated/prisma/client.js';
Migration Errors
If migrations fail, reset the local database:
cd apps/api
npx prisma migrate reset
This drops all data and re-runs all migrations from scratch.
Authentication
"Invalid email or password" on Login
This generic error message is shown for both wrong email and wrong password to prevent email enumeration. Double-check both credentials.
If you forgot your password, use the admin reset endpoint (MVP only):
curl -X POST https://your-domain.com/api/v1/auth/reset-password \
-H "X-Admin-Token: YOUR_JWT_SECRET" \
-H "Content-Type: application/json" \
-d '{"email": "your@email.com", "new_password": "newpassword123"}'
The X-Admin-Token value is your JWT_SECRET from the .env file.
Session Token Expired
Session tokens expire after 30 days of inactivity. If you receive a 401 error with "Invalid or expired token", log in again to get a new token.
Can't Connect to Server (iOS)
If ServerURLView shows "Can't connect to server":
- Verify the server URL is correct (should end with
/api/v1/healthresponds) - Check that the server is reachable from your device (same network or public URL)
- Ensure HTTPS is configured (iOS requires secure connections)
- Try the health endpoint directly:
curl https://your-server.com/api/v1/health
Rate Limit Exceeded
Auth endpoints are rate-limited to 5 requests per minute per IP. If you see a 429 error:
- Wait for the time specified in the
Retry-Afterheader - Avoid rapid login attempts
- For testing, restart the API to clear the in-memory rate limit cache
iOS
Xcode Simulator Not Found
Xcode may require downloading the iOS simulator runtime separately:
- Open Xcode
- Go to Xcode > Settings > Platforms
- Download the iOS 17.x runtime
Check which simulators are available and use one that matches:
- Use
iPhone 15 ProwithOS=17.5(or whichever runtime you installed)
Check available simulators:
xcrun simctl list devices
App Shows Onboarding After Fresh Install
This is expected behavior if the auth flow is not yet fully implemented. The app detects no Keychain token and shows the onboarding screen.
Keychain Persists After Uninstall
iOS Keychain data survives app deletion. Baby Basics uses reinstall detection to prevent stale tokens:
- On first launch, check
UserDefaults.bool(forKey: "hasRunBefore") - If
false, clear all Keychain items - Set
hasRunBefore = true
This ensures a clean slate after reinstalling the app.
Deployment
All POST Requests Return 500 (PrismaClientValidationError)
Symptom: GET requests work fine (dashboard loads, timeline loads), but all save/create operations fail silently on iOS. Server logs show PrismaClientValidationError: Unknown argument 'field_name'.
Root cause: The Dockerfile's COPY . . in the build stage copies a stale src/generated/prisma/ from the host filesystem, overwriting the freshly generated Prisma client from the deps stage. The stale client doesn't know about fields added after it was generated.
How it happens:
npm cion the server runsprisma generate(viapreparescript), creatingsrc/generated/prisma/- Later, new fields are added to the Prisma schema (e.g.,
milk_source,consistency) docker compose buildcopies the OLDsrc/generated/into the build stage viaCOPY . .- This overwrites the fresh output from the deps stage that ran
prisma generatewith the new schema - esbuild bundles the stale Prisma client types into
dist/server.js - At runtime, the Prisma client rejects the new fields
Fix:
-
Delete the stale generated files on the server:
rm -rf /opt/baby-basics/apps/api/src/generated -
Rebuild with no cache:
docker compose --env-file .env -f infra/docker-compose.yml -f infra/docker-compose.dev.yml build --no-cache api -
Restart the container:
docker compose --env-file .env -f infra/docker-compose.yml -f infra/docker-compose.dev.yml up -d api -
Verify POSTs work by tailing logs while testing a save on the device:
docker compose --env-file .env -f infra/docker-compose.yml -f infra/docker-compose.dev.yml logs api --follow
Prevention: src/generated is now in .dockerignore so COPY . . will never pick it up. If you see this error again, it means something regenerated src/generated/ on the server outside of Docker.
Deploy Script Fails with Rollback
Check the deploy logs for the specific error. Common causes:
- Database migration failure (schema conflict)
- Health check timeout (API didn't start in 30 seconds)
- Docker build failure (dependency issue)
Health Check Passes But Saves Fail
The health endpoint (/api/v1/health) only validates that the server starts and can reach the database. It does NOT verify that the Prisma schema matches the database schema. After deploying, always test a POST operation (create a feeding, diaper, etc.) to verify full functionality.
To check server logs for POST errors:
docker compose --env-file .env -f infra/docker-compose.yml -f infra/docker-compose.dev.yml logs api --tail=50 | grep -E "POST|statusCode.*[45]|err"
Backup Script Fails
Verify the backup directory exists and the Postgres container is running:
ls /opt/backups/
docker compose ps
Need More Help?
File an issue on GitHub.