Skip to content

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

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.

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions