镜像站点 · 本页由第三方 GitHub 只读镜像提供,非 GitHub 官方站点,不接受任何登录或凭据输入。前往 github.com
Skip to content

bug: Old Bun 1.3.3 fetch aborts requests after 300 s idle #5041

Open

Description

@Trosterud

Provide environment information

System:
OS: macOS 27.0.1
CPU: (10) arm64 Apple M2 Pro
Memory: 6.42 GB / 16.00 GB
Shell: 5.9 - /bin/zsh
Binaries:
Node: 24.19.0 - /opt/homebrew/bin/node
npm: 11.17.0 - /opt/homebrew/bin/npm
bun: 1.4.3 - /Users/be/.bun/bin/bun

Deployed on Trigger.dev Cloud (prod, eu-central-1), trigger.dev CLI / @trigger.dev/sdk 4.6.3, trigger.config.ts runtime: "bun".
The local machine is not involved: the failure happens in the deployed image (Bun 1.3.3).

Describe the bug

runtime: "bun" always deploys on triggerdotdev/bun:1.3-node20-bookworm, which ships Bun 1.3.3. On Bun 1.3.x, fetch aborts any request that receives no bytes for 300 seconds, throwing TimeoutError: The operation timed out. A per-request timeout or AbortSignal longer than 300 s doesn't help.

Long, non-streaming LLM calls (for example Vertex AI generateContent with large structured outputs) send nothing until they finish, so on Trigger.dev they fail at exactly 5:00.

What we see:

  • A task on runtime: "bun" (trigger.dev 4.6.3) makes one AI SDK generateText call to Vertex AI with timeout: 360_000.
  • The run fails exactly 300 s after the call starts with TimeoutError: The operation timed out. That's Bun's message; Node's equivalent reads "The operation was aborted due to timeout".
  • The same request completes under Bun 1.4.x.

Expected: a supported way to run on a Bun release without this limit. You already publish triggerdotdev/bun:1.4-bookworm (Bun 1.4.2), but the CLI can't select it.

Reproduction repo

No repository needed: the reproduction is a single self-contained Bun script with no dependencies (see "To reproduce"). It runs a local server, so no network or Trigger.dev account is required.

To reproduce

Save as bun-timeout.ts and run bun run bun-timeout.ts with each Bun version. It takes about 5.5 minutes.

const server = Bun.serve({
  port: 0,
  idleTimeout: 0,
  fetch(req) {
    if (new URL(req.url).pathname === "/silent") {
      // headers and body only after 330 s
      return new Promise((resolve) => setTimeout(() => resolve(new Response("done")), 330_000));
    }
    // headers immediately, then one byte every 10 s for 330 s
    let n = 0;
    return new Response(
      new ReadableStream({
        async pull(controller) {
          await Bun.sleep(10_000);
          controller.enqueue(new TextEncoder().encode("."));
          if (++n >= 33) controller.close();
        },
      }),
    );
  },
});
const t0 = Date.now();
const run = async (path: string, init?: object) => {
  try {
    await (await fetch(`http://localhost:${server.port}${path}`, init)).text();
    console.log(Bun.version, path, JSON.stringify(init ?? {}), "ok after", (Date.now() - t0) / 1000, "s");
  } catch (e: any) {
    console.log(Bun.version, path, JSON.stringify(init ?? {}), "failed after", (Date.now() - t0) / 1000, "s:", e?.name, e?.message);
  }
};
await Promise.all([run("/silent"), run("/trickle"), run("/silent", { timeout: false })]);
server.stop(true);

Results with the official @oven/bun-darwin-aarch64 builds:

Bun silent 330 s trickle 330 s silent + timeout: false
1.3.3 (current runtime: "bun" image) failed at 300.0 s, TimeoutError: The operation timed out. ok ok
1.3.14 (bun:1.3-bookworm) failed at 300.0 s ok ok
1.4.2 (bun:1.4-bookworm) ok ok ok
1.4.3 ok ok ok

The limit is an idle timeout: the response that trickles a byte every 10 s survives.

In a deployed task, any fetch that waits more than 300 s for the first byte fails the same way.

Suggested fix

Make Bun 1.4 selectable, the same way Node majors are. For example runtime: "bun-1.4" (and "bun-1.3"), mapped to the already-published triggerdotdev/bun:1.4-bookworm / bun:1.3-bookworm images. Or move runtime: "bun" to a current Bun release.

Where the version comes from (checked on v4.7.4 and main as of 2026-10-20):

  • packages/core/src/v3/schemas/build.ts: BuildRuntime = z.enum(["node", "node-22", "node-24", "node-26", "bun"]), so there's no way to choose a Bun version.
  • packages/cli-v3/src/deploy/buildImage.ts: BASE_IMAGE.bun / BUILD_IMAGE.bun → triggerdotdev/bun:1.3-node20-bookworm(-build).
  • base-images/images.json: that image copies oven/bun:1.3.3-slim. The same file already publishes bun:1.3-bookworm (oven/bun:1.3.14-slim) and bun:1.4-bookworm (oven/bun:1.4.2-slim).

#5003 (build.image.base overrides) would allow a workaround, but a supported runtime value would keep projects on images you publish and test.

Additional information

Workaround: passing Bun's non-standard timeout: false to fetch removes the cap. But it has to reach every HTTP client a task uses (AI SDKs, Google auth), and it also removes the only bound for calls that set no timeout of their own.

In production, every failed run of one of certain tasks over two months died at exactly 300s on this error. Another task survived only because its retry happened to finish under 300s.

Activity

  1. Lingu17 commented on Oct 22, 2026

    @Lingu17

    Looked into this a bit, a few notes in case they help whoever picks it up.

    Ran the repro script above with the official @oven/bun-windows-x64 builds and got the same result: 1.3.3 fails /silent at 300.5s with TimeoutError: The operation timed out., 1.4.2 passes all three.

    The part I wasn't sure about with mapping a bun-1.4 runtime to triggerdotdev/bun:1.4-bookworm is that the image has no node, so the bun Containerfile entrypoint would have to change from dumb-init node <entrypoint> to dumb-init bun <entrypoint>. To check that, I bundled managed-run-controller and ran it under Node 24 and Bun 1.4.2 against a stub supervisor, with TRIGGER_RUN_ID / TRIGGER_SNAPSHOT_ID set. Both behaved the same: same startup logs, same attempts/start and snapshots/since calls, same socket.io connect. So the run controller looks fine under bun, at least that far.

    Other bits I found along the way:

    • The latest publish run with all four images is 20260910-000000-0e9d021:
      • bun:1.3-bookworm@sha256:991ebbc955a793aaebfa619f9cd000d0c9d370a3b8673b705c8364d23a756717
      • bun:1.3-bookworm-build@sha256:4d90ab4b25ae3bd2f4eda468d94a475b2b73977c5be1497df17b18384cf5ea2d
      • bun:1.4-bookworm@sha256:8d3fdda4309808b9e12e388a4da20dcac72e67449a277b38d7aacc7c50b8e586
      • bun:1.4-bookworm-build@sha256:ae31fe34246e8b8b9725a8c5366c842ccce59742a0e3a57b42f43f1b251e84a9
    • Besides BuildRuntime and the image maps, === "bun" checks would need updating in cli-v3/src/build/plugins.ts, cli-v3/src/config.ts, rsc/src/build.ts, and the uid 1001 pin in supervisor/src/workloadManager/kubernetesPodSpec.ts.
    • dev runs tasks with the local bun, so it might be worth warning when the local version isn't the line the runtime deploys on. Otherwise someone on bun-1.4 with 1.3 installed locally won't see this bug in dev.

    I've got this working on a local branch (bun-1.3 / bun-1.4 runtimes, tests passing), but I'm not vouched, so I haven't opened a PR. Happy to share it if it's useful.

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

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions