Files
bun.sh/test/regression/issue/26387.test.ts
robobun 043fafeefa fix(http): set #js_ref in Request.toJS for server-created requests (#26390)
## 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>
2026-01-23 12:09:03 -08:00

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);