bun/no-unhandled-emitter-errors

Require an error listener on event emitters that Node.js functions return

When an event emitter emits error and nobody listens for it, the error is thrown instead. A try around the call doesn't catch it, because it happens later. So spawn("gti") with a typo, or createReadStream() on a file that's gone, ends the whole process.

The rule looks at what these functions return:

ModuleFunctions
node:child_processspawn, fork
node:clusterfork
node:fscreateReadStream, createWriteStream, watch
node:http, node:httpsrequest, get
node:http2, node:tlsconnect
node:netconnect, createConnection

Configure#

Off by default. To turn it on:

bunfig.toml
[lint.rules]
"bun/no-unhandled-emitter-errors" = "error" # or "warn"

Every option, set to its default:

bunfig.toml
[lint.rules]
"bun/no-unhandled-emitter-errors" = ["error", {
  factories = [], # list of objects
}]

Examples#

example.js1 problem
import { spawn } from "node:child_process";

const child = spawn("git", ["status", "--short"]);
child.stdout.on("data", show);
child.on("exit", done);

pipe() doesn't pass errors on, so the source still needs a listener:

example.js1 problem
import { createReadStream } from "node:fs";

createReadStream(file).pipe(response);
example.jsNo problems
import { spawn } from "node:child_process";

const child = spawn("git", ["status", "--short"]);
child.stdout.on("data", show);
child.on("exit", done);
child.on("error", fail);
example.jsNo problems
import { createReadStream } from "node:fs";

createReadStream(file).on("error", fail).pipe(response);

An emitter that's returned, exported or passed to another function isn't reported, because the listener might be added there. pipeline() handles its streams' errors:

example.jsNo problems
import { createReadStream } from "node:fs";
import { pipeline } from "node:stream/promises";

await pipeline(createReadStream(file), response);

export function open(path) {
  return createReadStream(path);
}

export const log = createReadStream("app.log");

Options#

OptionDefaultWhat it does
factories[]More functions that return an emitter, checked in addition to the table above. Each entry is { module, names }, with the import specifier and the function names. Without names, the default export is the function.
bunfig.toml
[lint.rules]
"bun/no-unhandled-emitter-errors" = ["error", {
  factories = [{ module = "ws", names = ["createWebSocketStream"] }],
}]
example.jswith { "factories": [{ "module": "ws", "names": ["createWebSocketStream"] }] }1 problem
import { createWebSocketStream } from "ws";

const stream = createWebSocketStream(socket);
stream.on("data", show);