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

Activity

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

Metadata

Metadata

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions