500 Internal Server Error: How to Find What Actually Broke
A 500 error means your server-side code threw an error it didn't handle. The page tells you nothing on purpose; the real message is in your logs. Where to look, the most common causes in AI-built apps, and how to stop users seeing a bare 500.
500 Internal Server Error is the server's way of saying "something went wrong in my code and I don't know what to tell you." Unlike a 502, the app did answer — it just answered with failure, because some code threw an error nobody caught.
The error page is deliberately vague. Showing visitors the real error would leak details about your code and database. The real message is in your logs.
Step 1: Find the real error
Where the logs live depends on your hosting:
| Host | Where to look |
|---|---|
| Vercel / Netlify | Project → Functions / Logs, filter by time of the error |
| Your own server | pm2 logs, journalctl -u myapp, docker logs myapp |
| Supabase Edge Functions | Function logs in the dashboard |
| Locally | The terminal running npm run dev |
Reproduce the error (load the page, submit the form), then look at the log lines from that moment. You're looking for a stack trace: an error message followed by a list of file names and line numbers. (How to read an error message)
If there's nothing in the logs, the app isn't logging errors. Add a top-level error handler that logs them, or set up error monitoring — it pays for itself the first time.
Step 2: Check the usual suspects
In AI-built apps, 500s in production come from a short list:
Missing environment variable. Works locally because .env has it; production doesn't. The log says something like undefined API key or Invalid URL. (Environment variables explained)
Database problem. Can't connect (wrong connection string, SSL required), a table that doesn't exist because a migration wasn't run, or a query that violates a constraint. (Database migrations)
Reading a property of undefined. Some data was missing — a user without a profile, an empty API response. (Cannot read properties of undefined)
A third-party API failed. Payment provider, email service or AI API returned an error or timed out, and the code assumed success.
File system assumptions. Writing to a folder that doesn't exist or isn't writable in production.
Case-sensitive file names. import './Header' works on Mac but fails on Linux if the file is header.tsx. (File paths explained)
For a fuller list of production-only bugs, see why your app works locally but not in production.
Step 3: Fix it, then handle it
Fix the cause. Then make sure the next unexpected error is handled gracefully:
- Catch errors at the edges. Every API route should catch errors, log them with context, and return a sensible response.
export async function POST(req) {
try {
// ... your code
} catch (err) {
console.error('create-order failed', { err })
return Response.json({ error: 'Something went wrong' }, { status: 500 })
}
}
- Return 4xx for the user's mistakes. Bad input is a
400, not a500. (Form validation) - Show a friendly error page instead of the default one — with a way back home.
- Get alerted. You shouldn't learn about 500s from a customer email.
Don't show stack traces to visitors
Development mode shows the full error in the browser — helpful locally, dangerous in production. Make sure production builds run with production settings (NODE_ENV=production, debug mode off in Flask/Django).
The summary
- A 500 means unhandled server-side code error.
- The real message is in your logs; reproduce, then read them.
- Usual causes: missing env vars, database issues, undefined data, failing third-party APIs.
- Catch errors at route boundaries, return 4xx for bad input, and set up alerts.
EasySpawn keeps your app's logs on the same server as your code, so Claude Code can read the stack trace, find the line and propose the fix in one session. See how it works or join the waitlist.
Related: 502 Bad Gateway · Debugging for Beginners · Error Monitoring for Beginners · HTTP Status Codes Explained
Keep reading
Why Is My Environment Variable Undefined? (Vite, Next.js, Node)
Your .env file has the value but the code sees undefined. The reasons are almost always the same: the wrong prefix (VITE_, NEXT_PUBLIC_), the wrong file name or folder, not restarting the dev server, build-time vs runtime, or the variable never being set in production.
502 Bad Gateway: What It Means and How to Fix It
A 502 means the server in front of your app (Nginx, Cloudflare, a load balancer) couldn't get a valid answer from your app. The usual causes — app crashed, wrong port, still starting, out of memory — and a step-by-step way to find which one.