500 Internal Server Error: what it means and how to fix it

500 Internal Server Error means the server hit an unexpected condition and couldn't complete the request. It's the generic "something broke" code: the server knows it failed but isn't telling you why. The real reason is almost always an exception or error in the application's logs.

HTTP/1.1 500 Internal Server Error
Content-Type: application/json

{"error": "internal_error", "message": "An unexpected error occurred", "request_id": "req_8f2c1a"}

Common causes

  • An unhandled exception. A null reference, a type error or a missing key in a code path nobody tested.
  • A failing dependency. The database is down, a query times out, or a downstream API call throws and isn't caught.
  • Configuration. A missing environment variable, a bad secret, a wrong file path, or a syntax error in .htaccess or another server config file.
  • Permissions. The process can't read a file or write to a directory it needs.
  • Unexpected input. A request with a shape the code didn't expect triggers a crash. This is still a server bug: bad input should get a 4xx.

How to fix it as a visitor

Reload the page once, then wait a few minutes. If it keeps happening on the same action, report it to the site with the time and what you were doing. A 500 is a server-side bug, and clearing your cache won't fix it.

How to fix it as a developer or ops

  1. Read the logs at the time of the request. Your app's stderr, journalctl -u myapp, kubectl logs, or your error tracker. Look for the stack trace. Logging a request ID in both the response and the log line makes this fast.
  2. Reproduce it. Replay the exact request with curl, including headers and body. Many 500s only happen with a specific payload.
  3. Check what changed. A recent deploy, config change, dependency upgrade or database migration is the usual suspect.
  4. Check dependencies. Is the database reachable? Are connection pools exhausted? Is a downstream API failing?
  5. Turn on detailed errors locally only. Debug pages (DEBUG=True, display_errors) help in development but leak internals in production.

On Apache and PHP hosts, a broken .htaccess rule or a PHP fatal error is the most common source of a bare 500. The Apache error_log names the line.

500s on a webhook endpoint

When your webhook handler throws, the provider sees a 500 and treats the delivery as failed. Most providers retry 5xx responses with backoff, but only for a limited window, and some don't retry at all. If the bug takes a day to fix, events sent during that day may be gone.

Two habits help:

  • Return 5xx only for problems that a retry can fix, such as a database outage. If the signature is invalid or the payload is malformed, return a 4xx so the provider stops retrying a request that will never succeed.
  • Acknowledge fast and process later. Store the raw event, return 200, and do the work from a queue. A bug in processing then never turns into a failed delivery.

If you put Webhook Relay in front of the endpoint, durable retries store each webhook first and retry it with exponential backoff for up to 30 days. Fix the bug, deploy, and the stored events are delivered. Delivery is at least once, so dedupe on the event ID (see idempotency). The webhook logs show the exact request and your endpoint's response for each attempt, which makes the failing payload easy to find.

When to return 500 from your own API

Return 500 when your server failed in a way the client couldn't have caused or prevented. Don't return it for validation errors (400 or 422), auth failures (401 or 403), or rate limits (429). When the outage is temporary and known, such as maintenance or overload, 503 Service Unavailable with Retry-After tells clients more. Never put stack traces in the response body. Return a request ID instead.

Frequently asked questions

What does 500 Internal Server Error mean?

HTTP 500 means the server ran into an unexpected condition and couldn't complete the request. It's a generic catch-all: the server knows something went wrong but isn't saying what. The real cause is in the application or server error logs.

How do I fix a 500 Internal Server Error?

Look at the application's error log for the stack trace at the time of the request. Common causes are an unhandled exception, a failed database query, a missing environment variable or config file, a file permission problem, or a syntax error in config such as .htaccess. Fix the cause and redeploy.

Is a 500 error caused by the client?

No. A 500 is a server-side error. The request may contain unexpected data that triggers a bug, but a well-behaved server should answer bad input with a 4xx code such as 400 or 422, not 500.

What is the difference between 500 and 502?

A 500 comes from the application itself when its own code fails. A 502 comes from a proxy or gateway in front of the application when it can't get a valid response from the app, for example because the app is down.

Should a webhook endpoint return 500 on failure?

Return a 5xx only for temporary failures you want retried, such as a database outage. Most providers retry 5xx responses. If the payload itself is invalid or the signature is wrong, return a 4xx instead so the provider knows retrying the same request won't help.