Summary
no-unsafe-promise-catch-error-property was created as a near-copy of no-unsafe-catch-error-property but did not receive two refinements the sibling has since gained (tracked by #42190). This is refinement drift: two rules with the same intent now diverge in coverage and diagnostic quality.
Gap 1 — computed string-literal access is not detected
The promise rule only inspects !node.computed member access, so err["message"] inside a .catch() callback is silently ignored. The current test suite even codifies this as valid:
// no-unsafe-promise-catch-error-property.test.ts ("valid: computed property access ...")
valid: [`promise.catch(err => { console.log(err["message"]); });`, ...]
The sibling no-unsafe-catch-error-property already flags computed string-literal access (err["message"], err["status"], ...) while intentionally leaving dynamic err[prop] out of scope — see its MemberExpression handler.
Gap 2 — no suggestion for non-message properties
In the promise rule, exitFunction attaches a getErrorMessage() suggestion only when prop === "message" and undefined otherwise. So err.stack, err.code, err.status, err.cause, err.name are flagged with no actionable fix. The sibling offers a wrapWithInstanceof suggestion for exactly these props:
// no-unsafe-catch-error-property.ts
wrapWithInstanceof: "Wrap with '({{errorVar}} instanceof Error ? {{errorVar}}.{{prop}} : undefined)' ..."
Suggested refinement
Port both behaviors from no-unsafe-catch-error-property to no-unsafe-promise-catch-error-property:
- Detect computed string-literal access
err["<prop>"] for the same UNSAFE_PROPERTIES set.
- Add a
wrapWithInstanceof suggestion for non-message props.
The two rules already share UNSAFE_PROPERTIES, isTypeofObjectCheck, and isNonNullGuardCheck verbatim — extracting the shared reporting logic would also prevent future drift.
Acceptance criteria
Filed by ESLint Refiner. Sibling reference: #42190. Verified against the two rule sources at time of writing.
Generated by 🤖 ESLint Refiner · 253.6 AIC · ⌖ 10.2 AIC · ⊞ 4.7K · ◷
Summary
no-unsafe-promise-catch-error-propertywas created as a near-copy ofno-unsafe-catch-error-propertybut did not receive two refinements the sibling has since gained (tracked by #42190). This is refinement drift: two rules with the same intent now diverge in coverage and diagnostic quality.Gap 1 — computed string-literal access is not detected
The promise rule only inspects
!node.computedmember access, soerr["message"]inside a.catch()callback is silently ignored. The current test suite even codifies this as valid:The sibling
no-unsafe-catch-error-propertyalready flags computed string-literal access (err["message"],err["status"], ...) while intentionally leaving dynamicerr[prop]out of scope — see itsMemberExpressionhandler.Gap 2 — no suggestion for non-
messagepropertiesIn the promise rule,
exitFunctionattaches agetErrorMessage()suggestion only whenprop === "message"andundefinedotherwise. Soerr.stack,err.code,err.status,err.cause,err.nameare flagged with no actionable fix. The sibling offers awrapWithInstanceofsuggestion for exactly these props:Suggested refinement
Port both behaviors from
no-unsafe-catch-error-propertytono-unsafe-promise-catch-error-property:err["<prop>"]for the sameUNSAFE_PROPERTIESset.wrapWithInstanceofsuggestion for non-messageprops.The two rules already share
UNSAFE_PROPERTIES,isTypeofObjectCheck, andisNonNullGuardCheckverbatim — extracting the shared reporting logic would also prevent future drift.Acceptance criteria
promise.catch(err => log(err["message"]))is flagged (update the now-incorrect "valid" test to "invalid").err.stack/err.code/err.status/err.cause/err.namein a.catch()callback each carry awrapWithInstanceofsuggestion.err[prop](non-literal) remains out of scope (no diagnostic), matching the sibling.Filed by ESLint Refiner. Sibling reference: #42190. Verified against the two rule sources at time of writing.