500 Internal Server Error
The vaguest status code in HTTP, on purpose. A 500 tells the outside world almost nothing, which is good for security and bad for debugging, unless you know where the real error went.
When a web application throws an exception that nothing catches, the framework or server has to send something back. That something is almost always 500 Internal Server Error. It is the HTTP equivalent of a shrug, and by design it carries no detail. The useful information is in a log file somewhere, and the most common 500 mistake is not knowing where.
What the spec says#
RFC 9110 §15.6.1 is one sentence long: a 500 "indicates that the server encountered an unexpected condition that prevented it from fulfilling the request." The surrounding 5xx section adds that the server "is aware that it has erred," and, except for HEAD requests, "SHOULD send a representation containing an explanation of the error situation, and whether it is a temporary or permanent condition."
The key word is unexpected. If you can anticipate a failure, there is usually a more specific code: a bad request is a 400, a missing record is a 404, an upstream dependency that failed is often better described as 502, 503 or 504. A 500 should mean "this is a bug or a broken environment."
Invalid email address in a signup form → 500 (the database constraint threw)
Validate first and return 400 or 422 with the field that failed
Every 500 you can trace to bad input is a missing validation step. The OWASP Error Handling Cheat Sheet likewise suggests reserving 5xx for failures the server cannot handle and using 4xx for client-caused errors.
Common causes#
| Cause | Typical clue | Where to look |
|---|---|---|
| Unhandled exception in application code | Only certain pages or inputs fail | App log / error tracker stack trace |
| Null or undefined value | TypeError, AttributeError, NullPointerException | Stack trace; see JavaScript errors and Python errors |
| Missing environment variable or secret | Everything fails right after a deploy | Startup logs; diff config between environments |
| Database unreachable or migration not run | "relation does not exist", connection refused | App log; database log |
| File permission or path error | Uploads or templates fail | App log; web server error log |
| Bad server configuration | Every request on a virtual host fails | Web server error log; config test (nginx -t) |
| Dependency upgraded with breaking change | Started after an install or rebuild | Lockfile diff; changelog |
| Resource exhaustion | Fails under load, works at night | Memory, disk and file-descriptor metrics |
How to debug a 500#
1. Reproduce it and capture the request#
# Status, headers and body in one go
curl -i https://example.com/checkout
# Many stacks return a request ID header; note it for the log search
curl -si https://example.com/checkout | grep -i -E "^(x-request-id|x-correlation-id|cf-ray):"
2. Read the right log#
Work from the inside out. The error you need is usually in the first of these that exists:
- Your error tracker or application log. This is where the stack trace lives.
- The application server's stdout/stderr. On a systemd host,
journalctl -u myapp --since "10 min ago"; in a container,docker logsorkubectl logs. - The web server or reverse proxy error log. For nginx, the path set by
error_log, commonly/var/log/nginx/error.log. Caddy writes to its configured log output (often the systemd journal).
# Watch logs live while you reproduce the error
sudo tail -f /var/log/nginx/error.log
journalctl -u myapp -f
# Count 500s per path in an nginx access log (combined format)
awk '$9 == 500 {print $7}' /var/log/nginx/access.log | sort | uniq -c | sort -rn | head
3. Ask "what changed?"#
Most 500s that appear suddenly coincide with a deploy, a config change, a dependency update, an expired credential or certificate, or a full disk. Check the deploy history before you start reading code.
4. Fix the code path, then the response#
Fix the bug, then make sure the failure is handled. Anything you can predict should become a specific 4xx or 5xx with a helpful body. Anything you cannot predict should still reach a global error handler that logs everything and returns a clean, generic 500.
Never ship a stack trace#
The OWASP cheat sheet warns that unhandled errors "can assist an attacker in this initial phase," and its example shows a raw Java stack trace that revealed the framework and server versions. The goal, in its words, is that "a generic response is returned by the application but the error details are logged server side." Turn off debug modes (Django's DEBUG, Flask's debugger, verbose PHP display_errors) in production.
HTTP/1.1 500 Internal Server Error
Content-Type: text/plain
Traceback (most recent call last):
File "/srv/app/payments.py", line 88, in charge
psycopg2.OperationalError: FATAL: password authentication failed for user "app_prod"HTTP/1.1 500 Internal Server Error
Content-Type: application/problem+json
{"type": "about:blank", "title": "Internal Server Error", "status": 500,
"detail": "Something went wrong on our side. Please try again shortly.",
"instance": "/errors/req_8f2c41"}The first response leaks a file path, a library and a database username. The second uses RFC 9457 problem details and gives support a reference to look up in the logs.
A minimal global handler#
// Express: register last, after all routes
const { randomUUID } = require("node:crypto");
app.use((err, req, res, next) => {
const id = req.get("x-request-id") || randomUUID();
console.error({ id, path: req.path, err }); // full detail, server-side only
res.status(500)
.type("application/problem+json")
.json({ type: "about:blank", title: "Internal Server Error",
status: 500, detail: "Unexpected error.", instance: `/errors/${id}` });
});
500 and search engines#
Google's documentation says that for 500 errors "Google decreases the crawl rate for the site," and that for server errors generally, "already indexed URLs are preserved in the index, but eventually dropped" (source). A brief outage is recoverable. A template bug that returns 500 on every product page for a week is not something to leave until Monday.
The reverse mistake is just as common: catching the error and rendering an error page with 200 OK. Google's soft-404 guide lists "a broken connection to the database" as one cause of soft 404s. An error page should carry an error status.
If you are a visitor#
- Wait a moment and reload once. Transient failures often clear on their own.
- If the error happens only when you submit a form, try simpler input (for example, no emoji or unusual characters in a name field) in case that is triggering the bug.
- Check the service's status page or social accounts for an outage notice.
- If you report it, include the time, the page and any reference ID on the error page. That is what the operators need to find it in their logs.
Frequently asked questions
What does 500 Internal Server Error mean?
RFC 9110 defines it as the server having encountered an unexpected condition that prevented it from fulfilling the request. It is the generic catch-all for server-side failures, usually an unhandled exception or a configuration error.
Is a 500 error my fault as a visitor?
Almost never. 5xx codes mean the server has erred. Reloading after a short wait sometimes works if the failure was transient, but the fix is up to the site's operators.
Where do I find the cause of a 500 error?
In the server-side logs, not the browser. Check your application's log or error tracker first, then the web server or reverse proxy error log (for example nginx's error_log), then the platform logs (systemd journal, container logs, or your host's log viewer).
Should an API show the error message in a 500 response?
Show a short generic message and a request or correlation ID, and log the details server-side. OWASP warns that detailed error output, such as stack traces, helps attackers learn about your stack.
Do 500 errors affect SEO?
Google says 500 errors make it decrease the crawl rate for a site, and that URLs which persistently return server errors are eventually dropped from the index. Short, rare outages are recoverable; long-running ones are not.
Sources
Every factual claim on this page links to one of these. Checked October 2026. See how we source.
- RFC 9110 §15.6.1: 500 Internal Server Error rfc-editor.org
- RFC 9110 §15.6: Server Error 5xx rfc-editor.org
- OWASP Error Handling Cheat Sheet cheatsheetseries.owasp.org
- OWASP: Improper Error Handling owasp.org
- RFC 9457: Problem Details for HTTP APIs rfc-editor.org
- Google Search Central: How HTTP status codes affect Google Search developers.google.com
- Google Search Central: Troubleshoot crawling errors developers.google.com
- MDN: 500 Internal Server Error developer.mozilla.org