Skip to content

Commit f42535c

Browse files
fix: gracefully handle undefined req.body
When non-JSON content types are sent, express.json() does not parse the body, resulting in `req.body` being undefined. Trying to destructure properties directly from it causes a TypeError and crashes the server with a 500 error. Added a fallback (`|| {}`) during destructuring to handle this case cleanly and return a 400 Bad Request instead. Also added tests to ensure this robustness. Co-authored-by: shenald-dev <245350826+shenald-dev@users.noreply.github.com>
1 parent b73f03e commit f42535c

4 files changed

Lines changed: 24 additions & 3 deletions

File tree

.jules/bolt.md

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,4 +27,11 @@ Learning:
2727
The generic error handler in the API was returning a 500 status code but was not covered by any automated tests, leaving a gap in coverage for unexpected server-side failures.
2828

2929
Action:
30-
Added a test case in `tests/api.test.js` that intentionally mocks a failure in an internal dependency (`crypto.randomUUID`) to trigger the generic error handler. The test asserts that the handler returns a 500 status code and a sanitized JSON response (`{ error: 'Internal server error' }`) without leaking stack traces. Additionally, `console.error` was temporarily suppressed during the test to keep test output clean.
30+
Added a test case in `tests/api.test.js` that intentionally mocks a failure in an internal dependency (`crypto.randomUUID`) to trigger the generic error handler. The test asserts that the handler returns a 500 status code and a sanitized JSON response (`{ error: 'Internal server error' }`) without leaking stack traces. Additionally, `console.error` was temporarily suppressed during the test to keep test output clean.
31+
## 2026-03-21 — Prevent 500 Error Crash from Undefined req.body
32+
33+
Learning:
34+
In Express, when a POST request is sent with a non-JSON `Content-Type` (like `text/plain`), the `express.json()` middleware does not parse the body, resulting in `req.body` being `undefined`. Destructuring properties directly from `req.body` (e.g., `const { model, messages } = req.body;`) without a fallback will throw a `TypeError`, leading to an unhandled 500 Internal Server Error.
35+
36+
Action:
37+
Modified the `/v1/chat/completions` endpoint to safely destructure using a fallback (`const { model, messages } = req.body || {};`). This ensures the endpoint gracefully catches missing parameters and correctly returns a `400 Bad Request` instead of crashing. Added a test in `tests/api_robustness.test.js` to prevent regressions.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
"scripts": {
77
"start": "node src/index.js --server",
88
"dev": "nodemon src/index.js --server",
9-
"test": "node tests/test.js && node tests/api.test.js",
9+
"test": "node tests/test.js && node tests/api.test.js && node tests/api_robustness.test.js && node tests/heavy_computation.test.js",
1010
"benchmark": "node benchmarks/run.js",
1111
"docker:build": "docker build -t shenald/one-api .",
1212
"docker:run": "docker run -p 3000:3000 shenald/one-api"

src/index.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ app.use((err, req, res, next) => {
3232

3333
// API endpoints
3434
app.post('/v1/chat/completions', (req, res) => {
35-
const { model, messages } = req.body;
35+
const { model, messages } = req.body || {};
3636
if (!model || !messages) {
3737
return res.status(400).json({ error: 'Missing model or messages' });
3838
}

tests/api_robustness.test.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
const { test } = require('node:test');
2+
const assert = require('node:assert');
3+
const request = require('supertest');
4+
const { app } = require('../src/index.js');
5+
6+
test('POST /v1/chat/completions handles undefined req.body (e.g. non-JSON content-type)', async () => {
7+
const res = await request(app)
8+
.post('/v1/chat/completions')
9+
.set('Content-Type', 'text/plain')
10+
.send('some text');
11+
12+
assert.strictEqual(res.status, 400);
13+
assert.strictEqual(res.body.error, 'Missing model or messages');
14+
});

0 commit comments

Comments
 (0)