Skip to content

[Bug]: JS SDK: passing logger makes every API call fail on Node with "onResponse: must return new Response() when modifying the response" #1986

Open

Description

@KarlFredrikssonEthira

Sandbox ID or Build ID

None. The call fails before a sandbox is created.

Environment

  • e2b 2.32.0 and 2.56.0 (latest). Both reproduce.
  • Node.js 24.14.1 (macOS and Linux/Alpine)
  • openapi-fetch 0.14.1 (bundled with 2.32.0) and 0.17.0 (bundled with 2.56.0)
  • undici resolvable, which is always the case because e2b depends on it

Timestamp of the issue

2026-10-14 20:00 UTC onwards (when we started passing logger). It reproduces every time.

Frequency

Happens every time

Expected behavior

Passing a logger in the connection options (for example Sandbox.create({ logger })) only adds logging, and the request behaves as it does without one.

Actual behavior

On Node, every API call made through ApiClient throws before the response is handled:

Error: onResponse: must return new Response() when modifying the response
    at coreFetch (node_modules/openapi-fetch/dist/index.mjs:...)

Without logger, the same call works.

Cause: On Node the SDK fetches through the npm undici (loadUndici() / buildApiFetcher in src/api/http2.ts), so responses are instances of undici.Response, not globalThis.Response. When a logger is set, createApiLogger (packages/js-sdk/src/logs.ts) installs a middleware whose onResponse returns the response it received. openapi-fetch treats any truthy onResponse result as a replacement response and requires result instanceof Response, checked against the global Response. undici.Response !== globalThis.Response, so the check fails.

Under Bun (and in browsers) the SDK uses the global fetch, so the classes match and the bug doesn't show. That's probably why it hasn't been noticed.

Suggested fix: don't return the unchanged response (or request). In openapi-fetch, returning undefined from a middleware means "unchanged":

export function createApiLogger(logger: Logger): Middleware {
  return {
    async onRequest({ request }) {
      logger.info?.(`Request ${request.method} ${request.url}`)
    },
    async onResponse({ response }) {
      if (response.status >= 400) {
        logger.error?.('Response:', response.status, response.statusText)
      } else {
        logger.info?.('Response:', response.status, response.statusText)
      }
    },
  }
}

Reproduction

No E2B account needed; a local stub server stands in for the API. Run with node repro.mjs (Node 24, npm i e2b):

import http from 'node:http'
import { Sandbox } from 'e2b'

const server = http
  .createServer((req, res) => {
    res.writeHead(500, { 'content-type': 'application/json' })
    res.end('{"code":500,"message":"stub api reached"}')
  })
  .listen(0)
await new Promise((r) => server.once('listening', r))
const apiUrl = `http://127.0.0.1:${server.address().port}`
const apiKey = 'e2b_' + '0'.repeat(40)

for (const logger of [undefined, { warn() {}, error() {} }]) {
  try {
    await Sandbox.create({ apiKey, apiUrl, logger })
  } catch (e) {
    console.log(logger ? 'with logger:   ' : 'without logger:', e.message)
  }
}
const undici = await import('undici')
console.log('undici.Response === globalThis.Response:', undici.Response === globalThis.Response)
server.close()

Output:

without logger: 500: stub api reached
with logger:    onResponse: must return new Response() when modifying the response
undici.Response === globalThis.Response: false

Under bun repro.mjs, both lines print 500: stub api reached.

Activity

  1. devin-ai-integration commented on Oct 15, 2026

    @devin-ai-integration
    Contributor

    Triage

    • type: bug
    • priority: high
    • complexity: small
    • affected_area: js-sdk/api logger middleware (createApiLogger in src/logs.ts, undici fetcher in src/api/http2.ts)
    • actionable: yes
    • needs_clarification: false
    • summary: On Node, passing a logger in connection options makes every ApiClient call fail with "onResponse: must return new Response() when modifying the response", because the logger middleware returns the unchanged undici Response, which fails openapi-fetch's instanceof globalThis.Response check. The issue includes a repro and a suggested fix (return undefined from onRequest/onResponse).

    Written by Devin

  2. CloudCorpRecords commented on Oct 16, 2026

    @CloudCorpRecords

    Hi, I would like to work on this. Plan: in the JS SDK, fix the openapi-fetch logging path so passing a custom logger does not break API calls: where the onResponse middleware modifies the response, return a new Response as the triage note suggests (createApiLogger in src/logs.ts, the fetcher in src/api/http2.ts), and add a regression test with a logger configured on Node.

  3. CloudCorpRecords commented on Oct 16, 2026

    @CloudCorpRecords

    Withdrawing my claim: PR #1987 by KarlFredrikssonEthira already fixes this, and it opened before my claim did. My race check missed the cross-referenced PR. Thanks, and good luck landing it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingsdkImprovements or additions to SDKs

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions