Skip to main content

Understanding 500 Internal Server Errors in GET or POST Requests

Understanding 500 Internal Server Errors in GET or POST Requests

Key takeaways

  • A 500 means the server hit an unexpected condition while handling your request. The real cause is in the server’s logs, not in the response.
  • On a POST, the usual trigger is a body the code did not expect: the wrong Content-Type, a missing field, or a missing session or CSRF token.
  • A request that works in the browser but fails from a script or load test is usually missing headers or cookies the browser sends on its own.
  • If 500s appear only under load, look at capacity: exhausted connection or thread pools, timeouts to a database or another service, memory.

You get a 500 Internal Server Error on a GET or POST request when the server’s own code fails while handling it. RFC 9110 defines it as the server having “encountered an unexpected condition that prevented it from fulfilling the request”. Something in your request (a body, a header, a missing cookie) or in the server’s state (a full connection pool, a dead dependency) led to an unhandled error. The response rarely says which, so the answer is in the server logs. This guide covers the common causes for GET and POST, why a request can work in the browser and fail from a script, why 500s can appear only under load, and how to debug them.

What does a 500 Internal Server Error mean?

A 500 is the server’s generic failure code. MDN calls it a “catch-all” used when no more specific 5xx code fits, typically after an unhandled exception, a configuration error or an out-of-memory condition. It says the server failed, but not why. Well-behaved servers answer bad input with a 4xx code, so a 500 caused by your request usually means the server did not validate that input.

The neighbouring status codes help you narrow it down:

StatusWhat it means (RFC 9110)Where to look
400 Bad RequestThe server will not process the request because of a client error, such as malformed syntaxYour request
413 Content Too LargeThe request body is larger than the server will acceptBody size limits
415 Unsupported Media TypeThe body is in a format the endpoint does not support, often the wrong Content-TypeYour Content-Type header
500 Internal Server ErrorAn unexpected condition stopped the server from fulfilling the requestApplication logs
502 Bad GatewayA proxy or gateway got an invalid response from the server behind itThe upstream app; it may have crashed
503 Service UnavailableThe server is temporarily overloaded or in maintenanceCapacity, deploys
504 Gateway TimeoutA proxy or gateway did not get a response in time from the server behind itSlow upstream, proxy timeouts

If a body that is too large or in the wrong format comes back as a 500 instead of a 413 or 415, the server is not checking that input. That is worth reporting to whoever owns the API.

Why does my POST request return a 500 error?

A POST carries a body, and the body is the most common trigger. The server reads it according to the Content-Type header, and code that assumes a field exists throws when it does not. If the exception is not caught and turned into a 4xx response, the framework returns a 500.

The usual suspects, in the order worth checking:

  1. Body and Content-Type do not match. JSON sent as application/x-www-form-urlencoded, or form data sent with Content-Type: application/json, leaves the parser with nothing or with garbage. How parameters are sent in an HTTP POST request shows what each encoding looks like on the wire.
  2. A required field is missing or has the wrong type. A missing id, a string where the code expects a number, or a date in the wrong format ends in a null reference or a parse exception.
  3. No session cookie or CSRF token. A form POST that worked in the browser fails from a script that never logged in or never extracted the token from the page. The code then reads a user or token that is not there.
  4. The body is too large. It should be a 413, but some stacks fail further down and return a 500.
  5. The server is the problem. A database write fails, a disk is full, a dependency is down. Your request was fine.

Why does a GET request return a 500 error?

A GET has no body, so the trigger is in the URL, the headers, the cookies or the server’s state. Common causes: a missing or malformed query parameter the code parses without checking, a missing cookie the page assumes, a header the code reads without a fallback (Accept-Language parsed for the locale, User-Agent parsed for device detection), and failures behind the endpoint such as a database or cache that is down. The HTTP GET request explainer covers what a GET can and cannot carry.

Why does a request work in the browser but return 500 from a script or load test?

This is the case that started this post. In 2016, LoadFocus customers reported intermittent 500 errors in their load tests on requests that worked fine from a browser. The difference was the headers. A browser adds a set of headers to every request on its own, while a test tool sends only what you configure. Some applications assumed those headers were always present and failed when they were not.

The headers to compare first:

  • Accept, Accept-Encoding and Accept-Language: content negotiation, compression and locale.
  • User-Agent: k6 sends Grafana k6/<version> by default, and JMeter only sends a browser-like value if you add one in an HTTP Header Manager. Some apps and firewalls treat unknown agents differently.
  • Cookie: the session. A script that skips login has none.
  • Referer and Origin: some CSRF checks read them.
  • Content-Type: on any request with a body.

Host is not on the list: HTTP/1.1 clients must send it, and a server answers a request without it with a 400, not a 500. Connection: keep-alive is not needed either; it is the default in HTTP/1.1, and HTTP/2 forbids the header.

The fastest way to find the missing piece is to copy the working request from the browser. In Chrome DevTools, open the Network panel, right-click the request, and choose Copy > Copy as cURL. Run that command, confirm it succeeds, then remove headers one at a time until it fails. The same cURL command can become your load test: the free load test converters turn it into a k6 script or a JMeter test plan with the headers intact. In JMeter, the HTTP(S) Test Script Recorder can add a Header Manager to each recorded sampler, which keeps the browser’s headers in the test. If the request depends on a login token, the test has to extract and resend it; extracting the token from the login response in JMeter shows one way.

Why do 500 errors appear only under load?

When the same request succeeds at low load and fails at high load, the request is fine and the server is running out of something. Typical causes are an exhausted database connection pool, a full worker or thread pool, timeouts to a database or another service that the code reports as a 500, and memory pressure. Whether you see a 500, 502, 503 or 504 depends on where it fails: inside the application, or in a proxy or load balancer in front of it.

To tell these apart, note the concurrency at which the first errors appear and line it up with server metrics from the same minutes: pool usage, CPU, memory, garbage collection, and the response times of the database and downstream services. Errors that begin as response times climb point to a queue filling up. A connection pool that is too small for the load is one of the most common culprits; sizing database connection pools walks through it. An error that only appears under load is a capacity finding, not a functional bug, and the fix is tuning or scaling rather than a code change to the endpoint.

How to debug a 500 Internal Server Error

  1. Find the log entry. Search the application logs for the failing request by time, URL or request ID. The stack trace usually names the line and the input that broke it.

  2. Reproduce it with one request. Use the browser’s Copy as cURL, or write the request by hand, and run it once:

    curl -i -X POST https://api.example.com/orders \
      -H 'Content-Type: application/json' \
      -d '{"sku": "A1", "qty": 1}'

    -i prints the response headers, which sometimes include a request ID you can search for in the logs.

  3. Diff the working and failing requests. Compare method, URL, headers, cookies and body. Change one thing at a time.

  4. If it only fails under load, ramp up gradually. Increase concurrency in steps and record where errors begin. Then match that point against server metrics.

  5. Fix the server, not only the request. Once you know the input that caused it, the server should answer that input with a 4xx and a clear message. That turns the next occurrence into a client error the caller can fix.

Finding 500 errors with LoadFocus

After those 2016 reports, LoadFocus added a Browser Compatible Headers button to the test editor. One click adds Accept, Accept-Encoding, Accept-Language, Cache-Control, Pragma and a browser User-Agent to a request, so a cloud load test sends what a browser would. Tests can also set any custom header, cookie or Basic authentication on a request.

In the results, LoadFocus analyses errors and response codes and explains likely causes. Its charts show when errors started and how many virtual users were running at that moment, which is the concurrency point step 4 above asks for. You can also set a maximum error rate as a pass/fail threshold, so a run that starts returning 500s fails on its own. To catch 500s in production before users report them, API monitoring checks status codes, response bodies and response times on a schedule and alerts you when a check fails.

Frequently Asked Questions

What does a 500 Internal Server Error actually mean?

The server failed while handling the request, because of an unexpected condition such as an unhandled exception. The explanation is in the server’s logs, not in the response you got back. That is why guessing from the client side rarely helps.

Is a 500 error caused by my request or by the server?

By definition it is a server error. Your request can still be the trigger: a missing field or the wrong Content-Type can crash code that does not validate input. In that case the server should have returned a 4xx code, and both sides have something to fix.

Why do I get a 500 on POST but not on GET?

The POST carries a body, and the server has to parse and validate it. A body in the wrong format, a missing field or a missing CSRF token is the usual reason. Compare the body and the Content-Type header with a request that works.

Why do 500 errors appear only under load?

Usually exhausted connection pools, full thread pools or timeouts to a database or another service, not broken code. The same request succeeds when there is spare capacity, and that pattern is itself the finding.

What is the difference between a 500 and a 502, 503 or 504?

A 500 comes from the application itself. A 502 and a 504 come from a proxy or gateway that got a bad response, or no timely response, from the server behind it. A 503 means the server is temporarily overloaded or in maintenance.

How should I investigate a 500 error?

Find the matching entry in the server logs first. Then reproduce the error with a single request, and compare it with a request that works. If it only appears under load, ramp up in steps and note where errors begin, because that points to a capacity limit, not a functional bug.

Sources

  • IETF RFC 9110, HTTP Semantics, sections 15.5.1 (400), 15.5.14 (413), 15.5.16 (415), 15.6.1 (500), 15.6.3 (502), 15.6.4 (503), 15.6.5 (504) and 10.1.5 (User-Agent), read October 2026.
  • IETF RFC 9112, HTTP/1.1, section 3.2 (Host is required; a server answers a missing Host with 400), and RFC 9113, HTTP/2, section 8.2.2 (no Connection header), read October 2026.
  • MDN, 500 Internal Server Error, read October 2026.
  • Grafana k6 options reference (grafana.com/docs/k6/latest/using-k6/k6-options/reference) (default User-Agent), Apache JMeter component reference (HTTP Header Manager, recorder header capture), and Chrome DevTools Network features reference (Copy as cURL), read October 2026.

Chris

Head of Content at LoadFocus

Chris leads content and oversees development across the services this blog covers. The guides and tool comparisons here come out of the same decisions that shape what ships.

Weekly tips right in your inbox.

Don’t miss out on the latest testing tips and tricks, tools and news related to software testing.

Already +20,000 members in the list.

The Load Testing Platform with AI That Explains Your Results

Load test websites and APIs from 25 cloud regions, monitor page speed and uptime, and get AI analysis that explains your results in plain English.

Cloud load testing, website speed and API monitoring in one place.

Hi there! Can I share a cool thing I'm working on with you?

A software testing newsletter that sparks joy.

Our goal is to create helpful content for software developers and testers.

If you're not into it, you can unsubscribe instantly.