Skip to content

feat(bun): Add childProcessIntegration for Bun runtime #20237

@The-LukeZ

Description

@The-LukeZ

Problem Statement

The existing childProcessIntegration (in packages/node-core) captures breadcrumbs and errors for child processes and worker threads. It works by subscribing to Node.js's internal node:diagnostics_channel channels (child_process and worker_threads), which Node.js publishes to from its C++ layer when a subprocess is spawned.

This approach does not work on Bun for two reasons:

  • Bun fully implements the node:diagnostics_channel API, but does not publish to the child_process or worker_threads channels when spawning processes. The subscriptions are registered but never fire.

    Verified by testing: subscribing to diagnostics_channel.channel('child_process') on Bun never fires, even when spawning via node:child_process. Even with the not-deprecated method.

  • Bun exposes its own native subprocess API — Bun.spawn() / Bun.spawnSync() — which returns a Bun.Subprocess object. This has no EventEmitter; exit and error handling go through an onExit callback option and a proc.exited promise, not .on('exit') / .on('error').

As a result, users running Sentry on Bun get no child process breadcrumbs, even if they import and configure childProcessIntegration from the node sdk.

Solution Brainstorm

Since Bun doesn't hook into diagnostics_channel for subprocesses, the integration must intercept process creation differently. Two monkey-patch targets should do the trick:

  1. node:child_process compat layer — Bun implements the Node.js child_process module and its ChildProcess objects do support .on('spawn'), .on('exit'), and .on('error'). Patching cp.spawn and cp.fork is sufficient; exec / execFile delegate to spawn at the JS level. (Yes, that abbreviation is unfortunate)

  2. Bun.spawn — Bun's native API. Bun.Subprocess has no EventEmitter, so the integration wraps the caller's onExit callback to capture exit codes and spawn errors. Bun.spawn supports two call signatures that both need handling:

    • Bun.spawn(cmd: string[], options?)
    • Bun.spawn(options: { cmd: string[] } & SpawnOptions)

Worker threads are intentionally out of scope for now — node:worker_threads is not yet fully supported in Bun and important features are missing. Ref: 1, 2

A reference implementation is available as a Gist: https://gist.github.com/The-LukeZ/ca83a14e9ddb24295c74112a3c2ac9a2 (I've tested it and it doesn't error at least)

Idea of the Bun integration's setup():

setup() {
  // 1. Patch node:child_process (compat layer)
  for (const method of ['spawn', 'fork']) {
    const original = cp[method];
    cp[method] = function (...args) {
      const child = original.apply(this, args);
      captureChildProcessEvents(child, options); // same EventEmitter logic as Node integration
      return child;
    };
  }

  // 2. Patch Bun.spawn (native)
  const originalSpawn = Bun.spawn.bind(Bun);
  Bun.spawn = function (cmdOrOptions, spawnOptions) {
    const userOnExit = resolvedOptions.onExit;
    return originalSpawn(cmdOrOptions, {
      ...resolvedOptions,
      onExit(proc, exitCode, signalCode, error) {
        // addBreadcrumb on non-zero exit or error
        userOnExit?.(proc, exitCode, signalCode, error);
      },
    });
  };
}

Additional Context

I took the code from the integration from node-core to draft that Bun integration.

  • Affected package: A new integration in packages/bun.

  • Bun subprocess docs: https://bun.com/docs/runtime/child-process

  • Bun diagnostics_channel compatibility: https://bun.com/reference/node/diagnostics_channel — listed as "Fully implemented" for the API, but Bun does not internally publish to 'child_process' channel events.

  • The sw_vers guard from the Node integration should be preserved — Sentry pings /usr/bin/sw_vers on macOS to collect OS context and should not generate a breadcrumb for that.

  • I am not in a position to open a PR (not enough knowledge to follow the contribution guidelines and no time for all the setup), but a working reference implementation is provided in the Gist linked above for whoever picks this up.

Priority

React with 👍 to help prioritize this issue. Please use comments to provide useful context, avoiding +1 or me too, to help us triage it.

Metadata

Metadata

Assignees

No one assigned
    No fields configured for issues without a type.

    Projects

    Status

    Waiting for: Product Owner

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions