mirror of
https://github.com/oven-sh/bun
synced 2026-02-09 18:38:55 +00:00
## Summary - Fix Request.text() failure with "TypeError: undefined is not a function" after many requests on certain platforms - Set `#js_ref` in `Request.toJS()` for server-created requests, matching the existing pattern in `Response.toJS()` ## Root Cause When Request objects are created by the server (via `Request.init()`), the `#js_ref` field was never initialized. This caused `checkBodyStreamRef()` to fail silently when called in `toJS()` because `#js_ref.tryGet()` returned null. The bug manifested on macOS after ~4,500 requests when GC conditions were triggered, causing the weak reference lookup to fail and resulting in "TypeError: undefined is not a function" when calling `req.text()`. ## Fix The fix mirrors the existing pattern in `Response.toJS()`: 1. Create the JS value first via `js.toJSUnchecked()` 2. Set `#js_ref` with the JS wrapper reference 3. Then call `checkBodyStreamRef()` which can now properly access the JS value ## Test plan - [x] Added regression test that exercises Request.text() with 6000 requests and periodic GC - [x] Existing request tests pass - [x] HTTP server tests pass Fixes #26387 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Bot <claude-bot@bun.sh> Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
47 lines
1.4 KiB
TypeScript
47 lines
1.4 KiB
TypeScript
import { expect, test } from "bun:test";
|
|
|
|
// https://github.com/oven-sh/bun/issues/26387
|
|
// Request.text() fails with "TypeError: undefined is not a function" after ~4500 requests
|
|
test("Request.text() should work after many requests", async () => {
|
|
// Create a server that reads the request body using req.text()
|
|
using server = Bun.serve({
|
|
port: 0,
|
|
async fetch(req) {
|
|
try {
|
|
const body = await req.text();
|
|
return new Response("ok:" + body.length);
|
|
} catch (e) {
|
|
return new Response(`error: ${e}`, { status: 500 });
|
|
}
|
|
},
|
|
});
|
|
|
|
const url = `http://localhost:${server.port}`;
|
|
|
|
// Send many requests to trigger the GC conditions that caused the bug
|
|
// The original bug occurred around 4500 requests, but we use a higher number
|
|
// to ensure we trigger any GC-related issues
|
|
const requestCount = 6000;
|
|
|
|
for (let i = 0; i < requestCount; i++) {
|
|
const body = Buffer.alloc(100, "x").toString() + `-request-${i}`;
|
|
const response = await fetch(url, {
|
|
method: "POST",
|
|
body: body,
|
|
});
|
|
|
|
if (!response.ok) {
|
|
const text = await response.text();
|
|
throw new Error(`Request ${i} failed: ${text}`);
|
|
}
|
|
|
|
const responseText = await response.text();
|
|
expect(responseText).toBe(`ok:${body.length}`);
|
|
|
|
// Periodically run GC to increase likelihood of triggering the bug
|
|
if (i % 500 === 0) {
|
|
Bun.gc(true);
|
|
}
|
|
}
|
|
}, 60000);
|