500 Internal Server Error
The server encountered an unexpected condition that prevented it from fulfilling the request, with no more specific error available.
Defined in RFC 9110 §15.6.1
What 500 means
HTTP 500 Internal Server Error is the generic response defined in RFC 9110 for any server-side fault that has no more specific 5xx status assigned to it. It tells the client that the request itself was almost certainly valid and reached the server, but processing failed for reasons outside the client's control. Because it is a catch-all, a 500 carries almost no diagnostic information for the caller beyond confirming the failure happened on the server. The real cause always lives in application code, server configuration, or infrastructure, and finding it requires looking at server-side logs rather than the response body.
The most common trigger is an unhandled exception in application code: a null reference, a failed type coercion, a database query that throws instead of returning rows, or an unhandled promise rejection in Node.js. Frameworks like Express, Django, Rails, and Spring catch these exceptions at a top level and convert them into a generic 500 response so the process does not crash outright. In production, a well-configured framework logs the full stack trace server-side while showing the client only a bare error page, which is why a working request that starts throwing 500s usually points at a recent code deploy or a data edge case the code never anticipated.
Misconfiguration is just as common as bad code. On Apache, a syntax error in .htaccess, an unsupported directive, or a missing module referenced by RewriteEngine rules will make Apache refuse the request with a 500 before it even reaches PHP. PHP itself raises 500s for fatal errors such as a missing extension, a memory_limit exhausted mid-script, or a version mismatch between code and the installed PHP binary. Similar misconfiguration failures show up with wrong file permissions, an expired or malformed environment variable, or a framework running in production mode without required secrets set, all of which fail before any application logic executes.
Diagnosing a 500 always starts with the server's error log rather than the browser. Apache and nginx write a distinct error log separate from the access log, PHP-FPM logs fatal errors with a file and line number, and application frameworks typically emit a stack trace with a timestamp and request ID that can be correlated across load balancer, web server, and app logs. Centralized logging or an APM tool such as Sentry, Datadog, or CloudWatch makes this correlation far faster than SSH-ing into a box. Reproducing the failing request locally with the same input, and turning on verbose or debug logging temporarily, usually narrows the cause within minutes.
Common causes
- An unhandled exception or runtime error in application code crashes the request handler before a response is built.
- A syntax error or unsupported directive in an Apache .htaccess file causes Apache to reject the request outright.
- A PHP fatal error, such as a missing extension or an exhausted memory_limit, halts script execution mid-request.
- Database connection failures, timeouts, or query errors propagate up as an unhandled exception in the request path.
- Missing or misconfigured environment variables and secrets leave the application unable to initialize a required service.
- A recent deploy introduces a code path, dependency version, or migration that the production environment cannot satisfy.
How to fix a 500
If you are the client (browser user or API caller)
- Retry the request after a short delay, since some 500s are transient blips rather than permanent failures.
- Check whether the request payload is unusual, such as very large, unexpected characters, or edge-case values, and try a minimal version to see if it still fails.
- Capture the response body, timestamp, and any request ID header and share them with the API provider or site owner, since 500 responses rarely expose useful detail to the client.
- Avoid building automatic retry loops that hammer the endpoint, since a 500 caused by server overload will only get worse under repeated retries.
- If calling a third-party API, check the provider's status page before assuming the bug is in your own integration code.
If you run the server
- Wrap request handlers in centralized error-handling middleware so every unhandled exception is caught, logged with a stack trace, and turned into a clean response.
- Validate .htaccess and nginx or Apache configuration changes with a syntax check, such as apachectl configtest or nginx -t, before deploying them.
- Set PHP's error_reporting and log_errors so fatal errors are written to a log file instead of only crashing silently, and raise memory_limit where legitimate workloads need it.
- Add monitoring and alerting, such as Sentry, Datadog, or CloudWatch Logs, that surfaces 500 spikes immediately after a deploy so they can be rolled back quickly.
- Run database migrations and dependency upgrades in staging against production-like data before promoting them, and keep a fast rollback path for the release process.
Example
GET /api/orders/8842 HTTP/1.1
Host: api.example.com
Accept: application/json
HTTP/1.1 500 Internal Server Error
Content-Type: application/json
X-Request-Id: 7e9b6b2a-91c4
{
"error": "internal_server_error",
"message": "An unexpected error occurred. Reference ID 7e9b6b2a-91c4 was logged."
}Try it live
Our free status responder returns a real HTTP 500 you can point tests, monitors or a browser at.
GET https://mcp.httpstatus.com/status/500