Skip to content

Troubleshooting ​

Common failure modes and their fixes, grouped by area.

Boot & database ​

API won't start / crashes on boot in production The API boot-validates the four mandatory MSG91 templates (OFFER_ACCEPTED, OTP, BID_PLACED, BID_ACCEPTED + the two *_AUTO_REJECTED_LEAD_EXPIRED). Set them, or run with NODE_ENV != production locally where they're optional.

P2024 errors / requests returning 503 under load The Prisma pool is saturated. Raise DATABASE_POOL_SIZE (≈ (tier cap × 0.8) / processes) and/or DATABASE_POOL_TIMEOUT. Logins fast-fail separately via LOGIN_TIMEOUT_MS so a saturated pool returns a retryable 503 instead of hanging.

prisma migrate dev stalls against Supabase The transaction pooler closes the shadow-DB connection mid-migration. Use a direct (non-pooled) connection string for migrations, or apply via prisma db execute + prisma migrate resolve --applied (how several existing migrations were applied).

Type errors on Prisma fields (e.g. previousRefreshToken) Your generated client is stale: npx prisma generate --schema=prisma/schema.prisma.

Auth & sessions ​

Users get logged out unexpectedly Never collapse every refresh error to a logout. The web interceptor must treat a 5xx/timeout on /auth/refresh as transient (keep the session) and only a 401 as terminal. The server's rotation grace (REFRESH_TOKEN_GRACE_MS) covers the lost-response case; cross-tab refresh is serialised with the Web Locks API.

429 on login during testing Login limiters count failures only and are Redis-backed. Either use a TEST_OTP_PHONES number (rate-exempt) or clear the counter:

bash
redis-cli -u "$REDIS_URL" DEL "rl:login-phone:phone:+919876543210"   # add --tls for a rediss:// URL
# axes: otp | login-phone | login-device | login-ip | search

Rate limits & Redis ​

Heavy load test hammering Redis Redis holds only transient data (counters + jobs). Before any load test set RATE_LIMIT_DISABLED=true (the limiters are the biggest Redis consumer). Repointing REDIS_URL to a fresh instance loses nothing — there's nothing to migrate.

SMS & notifications ​

SMS not arriving but the app works Expected when a template is unset or MSG91 is unreachable — SMS is best-effort; the in-app notification (the bell) is authoritative and always fires. Check the worker logs and the Bull Board at /admin/queues.

Image upload does nothing locally R2 isn't configured. The upload middleware needs R2_* vars; without them the path is inert. Also: SVGs are rejected outright, and magic bytes are verified (not just MIME).

Search returns Postgres results, not Meilisearch Meilisearch falls back to Postgres pg_trgm when MEILI_HOST/MEILI_API_KEY are unset. After configuring, build the index: node --import tsx apps/api/src/scripts/reindex-batches.ts.

Engagement flows ​

422 MUST_VIEW_FIRST when placing an offer/bid No LeadView exists for (user, lead). Use the natural UI flow (Open lead → detail → Make Offer), or the /book endpoint / Buy Now, which auto-record the view. Direct hits to /offers / /bids that skip the view are rejected by design.

422 MESSAGING_LOCKED when sending a message The offer/bid isn't ACCEPTED. Messaging is gated on acceptance; only inquiry-anchored threads bypass the gate.

409 BATCH_HAS_STOCK deleting a batch A lot with live stock can't be deleted. Empty it first (off-platform sale / correction), or delete the product if it's the only lot.

CORS ​

Browser blocked by CORS Only FRONTEND_URL, ADMIN_URL, ecropto.com (+ subdomains), and — in non-production — any http://localhost:<port> are allowed. * is never allowed. Set the exact origin.

Windows / native binaries ​

Alpine image crashes: "Could not load the sharp module … linuxmusl-x64" Running npm install on Windows pruned other platforms' optional binaries from the lockfile. Fix:

bash
# remove the pruned entries, then re-add ALL platforms
npm install --package-lock-only
grep sharp-linuxmusl-x64 package-lock.json   # must be present before pushing

The Dockerfile smoke-tests require('sharp') after npm ci so this fails the build, not production boot.

Admin panel ​

Admin panel shows the wrong data / hits pilot dataVITE_API_URL is baked at build time; the panel's environment is whichever DB the API it targets uses. Locally the API often points at the live Supabase pilot DB — treat destructive actions (retention purge!) accordingly.

Can't sign into admin The seeded dev admin is +919900000098 / admin@cropto2026. +919900000099 is the QA sandbox farmer, not the admin.

Internal technical documentation — Cropto