---
title: "500 Internal Server Error"
url: https://erroneo.us/developers/http-500-internal-server-error/
description: "HTTP 500 means the server hit an unexpected condition. How to find the real cause in logs, the usual culprits, and why stack traces must never reach users."
type: guide
section: "Developers"
date_modified: 2026-10-20
publisher: erroneo.us
license: All rights reserved. Quote with attribution and a link.
---

# 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](https://www.rfc-editor.org/rfc/rfc9110#name-500-internal-server-error) 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](https://www.rfc-editor.org/rfc/rfc9110#name-server-error-5xx) 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`](https://erroneo.us/developers/http-502-vs-504/). A 500 should mean "this is a bug or a broken environment."

Wrong: ~~Invalid email address in a signup form → `500` (the database constraint threw)~~

Right: Validate first and return `400` or `422` with the field that failed

Why: Every 500 you can trace to bad input is a missing validation step. The [OWASP Error Handling Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Error_Handling_Cheat_Sheet.html) 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](https://erroneo.us/developers/javascript-errors/) and [Python errors](https://erroneo.us/developers/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:

1. **Your error tracker or application log.** This is where the stack trace lives.
2. **The application server's stdout/stderr.** On a systemd host, `journalctl -u myapp --since "10 min ago"`; in a container, `docker logs` or `kubectl logs`.
3. **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"}
```

Why: The first response leaks a file path, a library and a database username. The second uses [RFC 9457 problem details](https://www.rfc-editor.org/rfc/rfc9457) 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](https://developers.google.com/search/docs/crawling-indexing/http-network-errors)). 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](https://developers.google.com/search/docs/crawling-indexing/troubleshoot-crawling-errors). 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.

>

Track your 5xx rate, not just individual errors. A steady trickle of 500s from one endpoint is a bug backlog; a sudden jump across all endpoints is an incident. Both deserve alerts, just not the same kind.

## 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

1. [RFC 9110 §15.6.1: 500 Internal Server Error](https://www.rfc-editor.org/rfc/rfc9110#name-500-internal-server-error)
2. [RFC 9110 §15.6: Server Error 5xx](https://www.rfc-editor.org/rfc/rfc9110#name-server-error-5xx)
3. [OWASP Error Handling Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Error_Handling_Cheat_Sheet.html)
4. [OWASP: Improper Error Handling](https://owasp.org/www-community/Improper_Error_Handling)
5. [RFC 9457: Problem Details for HTTP APIs](https://www.rfc-editor.org/rfc/rfc9457)
6. [Google Search Central: How HTTP status codes affect Google Search](https://developers.google.com/search/docs/crawling-indexing/http-network-errors)
7. [Google Search Central: Troubleshoot crawling errors](https://developers.google.com/search/docs/crawling-indexing/troubleshoot-crawling-errors)
8. [MDN: 500 Internal Server Error](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Status/500)

---
Source page: https://erroneo.us/developers/http-500-internal-server-error/ · More: https://erroneo.us/llms.txt
