Skip to main content

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":

  1. Verify the server URL is correct (should end with /api/v1/health responds)
  2. Check that the server is reachable from your device (same network or public URL)
  3. Ensure HTTPS is configured (iOS requires secure connections)
  4. 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-After header
  • 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:

  1. Open Xcode
  2. Go to Xcode > Settings > Platforms
  3. Download the iOS 17.x runtime

Check which simulators are available and use one that matches:

  • Use iPhone 15 Pro with OS=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:

  1. On first launch, check UserDefaults.bool(forKey: "hasRunBefore")
  2. If false, clear all Keychain items
  3. 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:

  1. npm ci on the server runs prisma generate (via prepare script), creating src/generated/prisma/
  2. Later, new fields are added to the Prisma schema (e.g., milk_source, consistency)
  3. docker compose build copies the OLD src/generated/ into the build stage via COPY . .
  4. This overwrites the fresh output from the deps stage that ran prisma generate with the new schema
  5. esbuild bundles the stale Prisma client types into dist/server.js
  6. At runtime, the Prisma client rejects the new fields

Fix:

  1. Delete the stale generated files on the server:

    rm -rf /opt/baby-basics/apps/api/src/generated
  2. Rebuild with no cache:

    docker compose --env-file .env -f infra/docker-compose.yml -f infra/docker-compose.dev.yml build --no-cache api
  3. Restart the container:

    docker compose --env-file .env -f infra/docker-compose.yml -f infra/docker-compose.dev.yml up -d api
  4. 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.