HTTP status code · Success (2xx)
204 No Content
204 No Content means the request succeeded and there is deliberately no response body. It is the usual answer to a DELETE, to a PUT or PATCH that saves without echoing the resource, and to CORS preflight requests; the classic bug is client code calling response.json() on it.
| Class | 2xx, Success |
|---|---|
| Defined in | RFC 9110 §15.3.5 |
| Cacheable by default | Yes, heuristically cacheable |
| Safe to retry | No need; the request succeeded |
| Relevant headers |
|
What 204 means
RFC 9110, section 15.3.5, says a 204 ends with the header section: it cannot contain content or trailers. Headers still count and describe the resource after the action, so a 204 to a PUT with an ETag tells the client the new entity tag without resending the data.
The code also means "stay where you are". A form submitted to an endpoint that answers 204 leaves the browser on the current page, which is why the spec mentions save actions in document editors.
The Fetch standard treats 204 as a null body status. new Response("x", { status: 204 }) throws a TypeError, and response.json() on a real 204 rejects with "Unexpected end of JSON input".
When to use it
- DELETE /reports/42 that succeeded.
- PUT or PATCH when the client already has the data it sent and needs no echo.
- CORS preflight (OPTIONS) answers, analytics beacons sent with navigator.sendBeacon, and the classic "return 204 for /favicon.ico" trick.
Common causes
If you run the server
- The frontend crashes with SyntaxError: Unexpected end of JSON input because it parses every response as JSON, including the empty 204.
- The handler tries to send a body with 204: Express silently drops it, Go's Write returns http.ErrBodyNotAllowed, and a hand-rolled server may corrupt the next response on a keep-alive connection.
How to fix it
If you run the server
- In the client, check res.status === 204 (or the Content-Length) before calling res.json().
- If the client needs the updated object, return 200 with the body instead of 204.
How to send 204
app.delete('/reports/:id', (req, res) => {
res.status(204).end();
});// app/reports/[id]/route.ts
export async function DELETE() {
return new Response(null, { status: 204 });
}mux.HandleFunc("DELETE /reports/{id}", func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusNoContent) // 204
})from fastapi import FastAPI, Response
app = FastAPI()
@app.delete("/reports/{id}")
def delete_report(id: str):
return Response(status_code=204)location /api/ {
# Answer CORS preflight without hitting the app
if ($request_method = OPTIONS) {
add_header Access-Control-Allow-Origin "https://app.example.com";
add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE";
add_header Access-Control-Allow-Headers "Authorization, Content-Type";
add_header Access-Control-Max-Age 86400;
return 204;
}
proxy_pass http://app;
}Commonly confused with
- 204 vs 200
- 200 is expected to carry a body; 204 guarantees there is none, so clients must not try to parse one.
- 204 vs 205
- 205 Reset Content is also bodiless but additionally asks the client to reset the form or view that sent the request.
- 204 vs 404
- For a DELETE of something already gone, some APIs answer 404 and others 204 to keep DELETE idempotent from the client's view; pick one and document it.
Frequently asked questions
- Can a 204 response have a body?
- No. RFC 9110 says a 204 is terminated by the end of the header section and cannot contain content or trailers. Frameworks strip or reject any body you try to send.
- Should DELETE return 204 or 200?
- Return 204 when there is nothing useful to send back, which is the common case. Return 200 if you include something, such as the deleted object or a summary of what was removed.
- Why does fetch() throw on a 204 response?
- It does not; your parsing does. response.json() on an empty body rejects with "Unexpected end of JSON input". Check response.status === 204 before parsing.
- What does a browser do when a form submission gets a 204?
- It stays on the current page and does not navigate. That makes 204 useful for save or tracking endpoints where the user should not leave the page.
Last reviewed by Arielton Oberek.