Skip to content

.mount() fails with "ReadableStream has already been used" when aot: false #1667

@alecps

Description

@alecps

.mount() fails with "ReadableStream has already been used" when aot: false

What is the problem?

When using .mount() to mount a request handler that reads the request body, the request fails with ReadableStream has already been used if aot: false is set. The same code works correctly with the default aot: true.

This affects integrations like BetterAuth that rely on .mount() to handle authentication routes.

Environment

  • Elysia version: 1.4.21
  • Bun version: 1.3.5
  • Platform: Darwin 24.6.0 arm64

Reproduction

import { Elysia } from 'elysia'

// A simple handler that reads the request body (similar to what BetterAuth does)
async function mountedHandler(request: Request): Promise<Response> {
  console.log('[Handler] Received request:', request.method, request.url)
  console.log('[Handler] Body used?:', request.bodyUsed)

  const text = await request.text()
  console.log('[Handler] Body text:', text)

  const body = JSON.parse(text)
  return new Response(JSON.stringify({ received: body }), {
    headers: { 'Content-Type': 'application/json' }
  })
}

// ✅ Works with aot: true (default)
const serverAotTrue = new Elysia()
  .mount('/api', mountedHandler)
  .listen(3001)

// ❌ Fails with aot: false
const serverAotFalse = new Elysia({ aot: false })
  .mount('/api', mountedHandler)
  .listen(3002)

Test:

# This works (aot: true)
curl -X POST http://localhost:3001/api \
  -H "Content-Type: application/json" \
  -d '{"email":"[email protected]"}'
# Response: {"received":{"email":"[email protected]"}}

# This fails (aot: false)
curl -X POST http://localhost:3002/api \
  -H "Content-Type: application/json" \
  -d '{"email":"[email protected]"}'
# Response: ReadableStream has already been used
# Status: 500

Test Output

=== Test 1: POST to server with aot: true (default) ===
[Handler] Received request: POST http://localhost:3001/
[Handler] Body used?: false
[Handler] Body text: {"email":"[email protected]","password":"secret123"}
Status: 200
Raw response: {"received":{"email":"[email protected]","password":"secret123"}}
Result: ✅ PASS

=== Test 2: POST to server with aot: false ===
Status: 500
Raw response: ReadableStream has already been used
Result: ❌ FAIL

Note that with aot: false, the handler's logging statements never appear - the error occurs before the mounted handler is invoked. This suggests Elysia is consuming the request body somewhere in its middleware chain when aot: false, before passing it to the mounted handler.

Expected Behavior

Both servers should successfully pass the request to the mounted handler with an unconsumed request body. The aot setting should not affect whether mounted handlers can read the request body.

Actual Behavior

  • aot: true (default): ✅ Works correctly, handler receives request with bodyUsed: false
  • aot: false: ❌ Returns 500 with "ReadableStream has already been used", handler never called

Impact

This bug prevents using aot: false with any library that:

  1. Uses .mount() to handle requests
  2. Needs to read the request body with request.json() or request.text()

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions