Troubleshooting
Diagnose common setup, integration, content, and deployment failures.
Start with the smallest reproducible command, read the first meaningful error,
and fix configuration at its source. Avoid committing .env, generated
.source, or local build output while troubleshooting.
Install and build
| Symptom | Likely cause | Inspect | Safe fix |
|---|---|---|---|
pnpm install changes many dependencies or rejects the lockfile | Wrong package manager/version or edited lockfile | package.json, pnpm-lock.yaml | Use pnpm and pnpm install; do not delete the lockfile as a first step |
pnpm lint reports formatting | Biome diagnostics | Reported file, biome.json | Run pnpm format, review the diff, then rerun pnpm lint |
pnpm build cannot resolve an alias/module | Missing dependency, wrong casing, or stale generated content | Import path, tsconfig.json, package.json | Fix the import/dependency; regenerate Fumadocs content if the import is from .source |
| Development works but production build fails | Server rendering reaches invalid env/data or a Client/Server boundary error | First failing route in build output | Run pnpm build locally and fix that route rather than suppressing the error |
See Installation and Deployment.
PostgreSQL and Drizzle
| Symptom | Likely cause | Inspect | Safe fix |
|---|---|---|---|
| Connection refused/timeout | PostgreSQL is stopped, host/port is wrong, or hosted DB blocks the network | DATABASE_URL, provider network policy | Test the same URL with a PostgreSQL client; correct connectivity before changing schema |
| Authentication or database-not-found error | Wrong user/password/database, often special-character escaping | DATABASE_URL | Generate/copy a fresh provider URL; URL-encode credentials when constructing it manually |
relation ... does not exist | Schema was not applied to this database | drizzle.config.ts, src/lib/db/schema/ | Confirm the target database, then run pnpm exec drizzle-kit push for local/template setup |
| Auth breaks after editing auth schema | Better Auth adapter expectations and Drizzle tables diverged | src/lib/auth.ts, src/lib/db/schema/auth.ts | Update the schema deliberately and apply it to the correct database |
| Too many connections in production | Per-instance pools exceed provider limits | src/lib/db/index.ts, hosting pool settings | Use a pooled PostgreSQL endpoint and size pools for total instance concurrency |
The template has no committed migration history; do not assume
drizzle-kit migrate is ready. See Database.
Better Auth, cookies, and redirects
| Symptom | Likely cause | Inspect | Safe fix |
|---|---|---|---|
Login succeeds but the app still redirects to /auth/login | Cookie is absent, scoped to another origin, or blocked by HTTP/HTTPS/domain mismatch | Browser cookies, BETTER_AUTH_URL, request host | Use one canonical origin; set BETTER_AUTH_URL to it and clear stale cookies |
| Auth endpoint returns server errors | Missing/weak secret or database/email failure | BETTER_AUTH_SECRET, server logs, DATABASE_URL, Resend config | Generate a strong secret, fix the underlying service, restart the server |
| A protected API is reachable despite proxy assumptions | src/proxy.ts only redirects pages based on cookie presence and skips /api | Route Handler auth check | Call auth.api.getSession({ headers: await headers() }) inside every protected server boundary |
| Works locally, fails behind a proxy | Public origin/protocol is different from the configured auth URL | Forwarded host/proto, BETTER_AUTH_URL | Configure the canonical HTTPS URL and trusted proxy headers at the platform |
See Authentication.
OAuth callbacks
| Symptom | Likely cause | Inspect | Safe fix |
|---|---|---|---|
| Provider says callback/redirect mismatch | Registered URL differs by host, scheme, port, locale, or provider | OAuth dashboard, BETTER_AUTH_URL | Register {BETTER_AUTH_URL}/api/auth/callback/{provider} exactly |
| OAuth button fails immediately | Client ID/secret is missing or from a different app/environment | GITHUB_*, GOOGLE_*, provider dashboard | Use a matching credential pair and restart after changing env vars |
| Account linking is unexpected | Multiple providers use the same email and linking is enabled | src/lib/auth.ts | Review the template's linking policy before changing it; test existing accounts |
Resend email
| Symptom | Likely cause | Inspect | Safe fix |
|---|---|---|---|
| Verification/reset/contact returns a send error | Missing RESEND_API_KEY, invalid key, or provider rejection | Server logs, .env, src/lib/email/ | Use a valid server-only key and retry with a permitted recipient/sender |
| Works with a test sender but not your domain | Domain/DNS is unverified or fromEmail uses the wrong domain | Resend domain status, website-config.ts | Verify DNS, then use a sender on that exact domain |
| Message accepted but not delivered | Spam/bounce/suppression or recipient issue | Resend delivery events | Inspect provider events; do not repeatedly retry permanent bounces |
See Email.
Creem checkout and webhooks
| Symptom | Likely cause | Inspect | Safe fix |
|---|---|---|---|
| Checkout creation fails | Sandbox/live key, server index, and product ID do not belong together | CREEM_SERVER_IDX, CREEM_API_KEY, NEXT_PUBLIC_CREEM_PRODUCT_* | Use one environment's matching key and product IDs; rebuild after changing public IDs |
Webhook returns 401 Invalid signature | Wrong secret, missing creem-signature, or body/proxy was altered | CREEM_WEBHOOK_SECRET, webhook endpoint/logs | Copy the secret for the same Creem endpoint and send the raw provider request directly |
Webhook returns 500 about configuration | Secret is unset at runtime | Runtime env | Set CREEM_WEBHOOK_SECRET on the running deployment and restart/redeploy |
| Payment succeeds but UI remains unchanged | Event not handled, webhook not delivered, or dashboard page is still mock | Creem delivery log, /api/payment/notify/creem, DB rows | Replay a verified sandbox event; inspect order/subscription rows; connect the UI to those rows |
Use the exact webhook path /api/payment/notify/creem. See
Payments.
OpenAI chat
| Symptom | Likely cause | Inspect | Safe fix |
|---|---|---|---|
| Missing/invalid API key | OPENAI_API_KEY is absent or invalid | Server env and route logs | Set a valid server-only key and restart |
| Model not found/unsupported | Client picker/model string is unavailable through the configured provider | ChatBot.tsx, /api/chat request | Choose a supported model and enforce the same allowlist server-side |
| Search toggle returns no web results | Current code sends tools: {} | src/app/api/chat/route.ts | Configure a real server-side search tool or remove/disable the toggle |
| Stream stops with little UI feedback | Provider/connection error is not mapped into a product error state | Network response and server logs | Add structured stream error handling, timeouts, and user-safe feedback |
See AI Chat.
Replicate media
| Symptom | Likely cause | Inspect | Safe fix |
|---|---|---|---|
| Provider “not configured” | REPLICATE_API_TOKEN was missing when the lazy factory was created | Runtime env, src/lib/ai/*/index.ts | Set the token and restart the process |
Prediction creation returns 500 | Invalid model ID or model-specific input mapping | Route logs, provider implementation, Replicate prediction error | Compare createTask() input with that model's schema; do not blindly pass UI options |
| Polling never finishes | Remote job is slow/stuck, status is unknown, or client has no overall timeout | /query response, Replicate task | Inspect the task at Replicate; add bounded backoff, timeout, cancellation, and persistence |
| Success has no visible media | Output shape is not recognized or provider URL expired/CORS blocks download | taskInfo.output, URL extractor | Extend the relevant extractor; copy final assets to your own object storage |
See AI Media.
Fumadocs and MDX
| Symptom | Likely cause | Inspect | Safe fix |
|---|---|---|---|
Collection import or .source type is missing | Generated directory is stale/absent | .source/, source.config.ts, tsconfig.json | Stop dev, remove .source/, run pnpm dev or pnpm build |
| Build reports invalid frontmatter | Required schema field has wrong type/format | Failing MDX file, source.config.ts | Correct frontmatter; dates use YYYY-MM-DD, tags are arrays |
| Docs page is 404 or absent from nav | File/translation is missing or meta.json slug is wrong | content/docs/, nearest meta.json | Create the page pair and make the exact filename match the navigation slug |
| MDX component is undefined | Component is not in the map passed by that renderer | mdx-components.tsx, docs/blog/legal page | Register and pass a shared component map to the relevant renderer |
Do not edit .source by hand. See Content.
Internationalized routing
| Symptom | Likely cause | Inspect | Safe fix |
|---|---|---|---|
/en/... redirects or links look inconsistent | Default English locale uses localePrefix: "as-needed" | src/i18n/routing.ts, navigation helpers | Use @/i18n/navigation; expect English without /en and Chinese with /zh |
| New locale 404s | Locale was added in only one place or messages/content are missing | routing, request config, messages, proxy regex | Update every locale list and provide messages/content before linking it |
| API requests are unexpectedly localized | API was routed through locale middleware | src/proxy.ts matcher/early API return | Keep /api excluded from locale handling |
See Internationalization.
Docker
| Symptom | Likely cause | Inspect | Safe fix |
|---|---|---|---|
Container exits because server.js is missing | App was not built with standalone output or wrong stage/artifact was copied | next.config.mjs, Docker build log | Keep output: "standalone" and rebuild the provided multi-stage Dockerfile |
| Container runs but cannot reach PostgreSQL | localhost points to the container itself | Runtime DATABASE_URL, Docker network | Use the database service hostname/host gateway and test from the same network |
| Public config is stale despite runtime env change | NEXT_PUBLIC_* was inlined during pnpm build | Builder-stage env and deployment artifact | Supply public values at build time and rebuild the image |
| Uploaded files disappear | public/uploads is inside an ephemeral/replaced container | Upload route and volumes | Replace local writes with durable object storage; a volume alone still needs multi-instance design |
See Deployment and Storage.
Next.js 16 checks
- Async request APIs: type
paramsandsearchParamsas promises and await them. Also awaitheaders()andcookies(). proxy.ts, notmiddleware.ts: this template uses the Next.js 16 proxy convention. Do not add a second legacy middleware file from an old tutorial.- Server/Client boundaries: Client Components cannot be
async; browser hooks need"use client"; props crossing from server to client must be serializable. Keep secrets/database code server-only. - Build-time public env: changing
NEXT_PUBLIC_*after a build does not update the browser bundle. Rebuild/redeploy.
If a problem persists, capture the failing command, first relevant stack frame, route, HTTP status/response, and redacted environment variable names—not secret values. That is usually enough to make the next debugging pass decisive.
