Skip to content

eslint-factory: no-err-stack-then-string-fallback's suggestion applies getErrorMessage() without checking it's resolvable, break [Content truncated due to length] #49490

Description

@github-actions

Rule

no-err-stack-then-string-fallback (eslint-factory/src/rules/no-err-stack-then-string-fallback.ts).

Problem

The rule's only suggestion (replaceWithGetErrorMessage, lines 94-102) unconditionally rewrites the matched <errVar> instanceof Error ? <errVar>.stack : String(<errVar>) (or &&-guarded) ternary to getErrorMessage(<errVar>), with no check that getErrorMessage is actually imported/resolvable in the file. The message text itself even says "ensure getErrorMessage is imported from error_helpers.cjs before applying" (line 61) — i.e. the rule authors knew this was a precondition, but never encoded it as a check.

Three sibling rules that offer the identical getErrorMessage(...) suggestion already guard against exactly this failure mode with a hasResolvableLocalBinding(node, "getErrorMessage") check: no-json-stringify-error.ts, prefer-get-error-message-over-string.ts, and no-caught-error-interpolation.ts. no-err-stack-then-string-fallback.ts is missing this same gate.

Grounded evidence

actions/setup/js/copilot_sdk_driver.cjs:146-150:

if (require.main === module) {
  main().catch(err => {
    process.stderr.write(`[copilot-sdk-driver] unhandled error: ${err instanceof Error ? err.stack : String(err)}\n`);
    process.exit(1);
  });
}

This exactly matches the rule's <errVar> instanceof Error ? <errVar>.stack : String(<errVar>) pattern and correctly fires. But copilot_sdk_driver.cjs has zero references to getErrorMessage anywhere in the file (confirmed by grep) and never imports error_helpers.cjs. Accepting the suggested fix here replaces this line with getErrorMessage(err), which throws ReferenceError: getErrorMessage is not defined — inside the top-level unhandled-rejection handler itself, i.e. the fix silently breaks the last-resort error-reporting path for the entire script.

Ask

Add the same hasResolvableLocalBinding(node, "getErrorMessage") gate already used by no-json-stringify-error.ts / prefer-get-error-message-over-string.ts / no-caught-error-interpolation.ts to no-err-stack-then-string-fallback.ts, so the suggest array is empty (diagnostic still reported, just no unsafe autofix) when getErrorMessage isn't resolvable in scope.

Acceptance criteria

  • New test case: file without a getErrorMessage import/binding — rule still reports the diagnostic but suggest is empty (no unresolvable-reference autofix offered).
  • Existing test case(s) where getErrorMessage is resolvable continue to offer the suggestion unchanged.
  • Re-verify copilot_sdk_driver.cjs:148 after the fix: diagnostic still fires, no suggestion offered (until error_helpers.cjs is actually imported there).

Generated by 🤖 ESLint Refiner · agent · 669.3 AIC · ⌖ 7.12 AIC · ⊞ 4.9K ·

  • expires on Aug 7, 2026, 10:28 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