Skip to content

eslint-factory: no-caught-error-interpolation misses EventEmitter-style .on('error', err => ...) handler parameters #49720

Description

@github-actions

Rule

no-caught-error-interpolation (in eslint-factory/src/rules/no-caught-error-interpolation.ts). First quality review of this rule — no prior refinement issues filed.

Problem

isCaughtErrorVariableDef() only recognizes two binding shapes as "caught error" variables:

  1. A try/catch clause with a simple identifier param.
  2. The parameter of an inline function passed to .catch(fn) or .then(onFulfilled, onRejected) (via isInlineRejectionHandler, which requires the function's parent to be exactly that CallExpression).

A very common third shape is structurally identical but unrecognized: an inline arrow/function callback passed as the listener to an EventEmitter 'error' event — emitter.on('error', err => ...), .once('error', ...), .addListener('error', ...). Node guarantees the callback receives an Error object, so ${err} there has the exact same footgun the rule exists to prevent (redundant "Error: message" prefix, or "[object Object]" for non-Error emissions) — yet it is invisible to isInlineRejectionHandler, which only matches .catch/.then callees.

Grounded live occurrence

actions/setup/js/mcp_server_core.cjs:1052:

process.stdin.on("error", err => server.debug(`stdin error: ${err}`));

Here err is the parameter of an inline arrow function passed as the listener for the 'error' event on process.stdin (a stream/EventEmitter). This is a bare, unsafe interpolation of a real Error object, but no-caught-error-interpolation does not fire on it today.

Ask

  1. Extend the recognized "caught error variable" shapes to include the parameter of an inline ArrowFunctionExpression/FunctionExpression passed as the listener argument to .on(...)/.once(...)/.addListener(...) when the event-name argument is the string literal "error" (mirroring the .catch/.then detection style already used for isInlineRejectionHandler).
  2. Only the listener parameter itself should be flagged (first param, matching Node's (err) => ... signature for the 'error' event) — do not widen to other event names.
  3. Add test cases: valid (non-'error' event names, e.g. .on('data', ...), are not flagged; named/hoisted listener functions may remain out of scope per the existing "inline" restriction, but should get an explicit valid test case documenting that as intentional) and invalid (emitter.on('error', err => \...${err}...`), .once('error', ...), .addListener('error', ...)`).
  4. Re-verify mcp_server_core.cjs:1052 is flagged (and gets the String(err) fallback suggestion, since getErrorMessage is not imported there) once the fix lands.

Acceptance criteria

  • isCaughtErrorVariableDef (or an added helper) recognizes the first parameter of an inline callback passed to .on('error', ...)/.once('error', ...)/.addListener('error', ...).
  • New passing tests cover both the newly-caught case and the non-'error'-event exclusion.
  • mcp_server_core.cjs:1052 is confirmed to be a true positive after the fix (statically, since lint cannot be run live in this environment).

Generated by 🤖 ESLint Refiner · agent · 215.2 AIC · ⌖ 30.5 AIC · ⊞ 4.9K ·

  • expires on Aug 8, 2026, 10:33 PM UTC-08:00

Metadata

Metadata

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions