Summary
In no-unsafe-catch-error-property, hasGuard is a single frame-level flag. Any recognized guard (err instanceof Error, getErrorMessage(err), or typeof err === "object" + non-null) sets it for the entire catch frame, and at CatchClause:exit all collected unsafeNodes are skipped. As a result a guard that appears on a different branch than the unsafe access — or textually after it — still suppresses the report, producing false negatives.
Where
eslint-factory/src/rules/no-unsafe-catch-error-property.ts:71-109 — CatchClause:exit returns early / skips every unsafeNode whenever frame.hasGuard is set.
- Guard setters at
:112-121 (getErrorMessage), :125-138 (instanceof / typeof), and :140-162 (&& guard) set top.hasGuard = true without regard to source position or branch relative to the flagged access.
Failure example
catch (err) {
if (flag) core.info(err.message); // unguarded; runs when flag is true
if (err instanceof Error) log(err.stack); // guard on a DIFFERENT branch
}
The first .message access is unguarded at runtime, but the sibling-branch instanceof guard flips hasGuard, so nothing is reported. A guard placed textually after the access has the same suppressing effect.
Proposal
Make a guard cover only the accesses it actually dominates. Preferred: treat a guard as protecting accesses lexically within its guarded branch / consequent, or (minimum bar) require the guard test to precede the access in source order and share an enclosing block. Track guard scope per access rather than one boolean per frame.
Acceptance criteria
- An unguarded access on a sibling branch is reported even when another branch guards the error.
- An access textually before the only guard is reported.
- No new false positives: existing valid patterns (guard-then-access in the same branch; early-return non-null +
typeof === "object"; instanceof narrowing; getErrorMessage(err) before access) still pass. Run the full existing no-unsafe-catch-error-property.test.ts suite unchanged.
- Add tests for: sibling-branch guard, guard-after-access, and a nested-block guard that does dominate (still valid).
Non-duplicate
Distinct from the closed refiner issues (#46992-#46994, #47211-#47212), which target other rules. This is a precision/false-negative fix for the guard model in this rule.
Filed by ESLint Refiner (daily rule-quality refinement).
Generated by 🤖 ESLint Refiner · age00 317.3 AIC · ⌖ 13.1 AIC · ⊞ 4.6K · ◷
Summary
In
no-unsafe-catch-error-property,hasGuardis a single frame-level flag. Any recognized guard (err instanceof Error,getErrorMessage(err), ortypeof err === "object"+ non-null) sets it for the entire catch frame, and atCatchClause:exitall collectedunsafeNodesare skipped. As a result a guard that appears on a different branch than the unsafe access — or textually after it — still suppresses the report, producing false negatives.Where
eslint-factory/src/rules/no-unsafe-catch-error-property.ts:71-109—CatchClause:exitreturns early / skips everyunsafeNodewheneverframe.hasGuardis set.:112-121(getErrorMessage),:125-138(instanceof/typeof), and:140-162(&&guard) settop.hasGuard = truewithout regard to source position or branch relative to the flagged access.Failure example
The first
.messageaccess is unguarded at runtime, but the sibling-branchinstanceofguard flipshasGuard, so nothing is reported. A guard placed textually after the access has the same suppressing effect.Proposal
Make a guard cover only the accesses it actually dominates. Preferred: treat a guard as protecting accesses lexically within its guarded branch / consequent, or (minimum bar) require the guard test to precede the access in source order and share an enclosing block. Track guard scope per access rather than one boolean per frame.
Acceptance criteria
typeof === "object";instanceofnarrowing;getErrorMessage(err)before access) still pass. Run the full existingno-unsafe-catch-error-property.test.tssuite unchanged.Non-duplicate
Distinct from the closed refiner issues (#46992-#46994, #47211-#47212), which target other rules. This is a precision/false-negative fix for the guard model in this rule.
Filed by ESLint Refiner (daily rule-quality refinement).