Skip to content

eslint-factory: no-unsafe-catch-error-property — bare typeof err === 'object' guard is unsound for null #42435

Description

@github-actions

Summary

no-unsafe-catch-error-property accepts typeof err === 'object' as a sufficient guard that suppresses all unsafe-property warnings in the catch block:

// no-unsafe-catch-error-property.ts:105-123  (BinaryExpression handler)
// typeof varName === 'object' or 'object' === typeof varName  -> top.hasGuard = true

The test suite asserts the null-unchecked form as valid:

// no-unsafe-catch-error-property.test.ts:348 (valid)
`try { f(); } catch (err) { if (typeof err === 'object') { console.log(err.status); } }`

Why this is a false negative

typeof null === 'object'. So when the thrown value is null (or any non-Error object lacking the property), the guard passes and err.status is accessed anyway — null.status throws a TypeError, which is exactly the non-Error-throw failure mode this rule is meant to catch. The guard narrows nothing useful on its own; it gives a false sense of safety and silences the warning on genuinely unsafe code.

Note the very next valid fixture (line 349) does it correctly: typeof err === 'object' && err !== null. The rule should require that companion null check.

Acceptance criteria

  • A bare typeof err === 'object' (with no err !== null / err != null / truthiness companion in the same guard condition) no longer marks the frame as guarded.
  • typeof err === 'object' && err !== null (and equivalents: err != null, a preceding if (!err) return;, err && typeof err === 'object') continue to be accepted.
  • err instanceof Error and getErrorMessage(err) guards are unchanged.
  • Update no-unsafe-catch-error-property.test.ts: move the bare-typeof case (line 348) from valid to invalid, keep the null-checked cases (lines 349, 430) valid.
  • Apply the same tightening to no-unsafe-promise-catch-error-property, which shares the identical typeof === 'object' guard logic, for parity.

Relationship to existing issues

Distinct from #42189 (whole-frame vs. flow-sensitive guard placement). This is about the semantic strength of one specific guard form, not where it appears.

Generated by 🤖 ESLint Refiner · 185.1 AIC · ⌖ 12.4 AIC · ⊞ 4.7K ·

  • expires on Jul 6, 2026, 10:44 PM UTC-08:00

Metadata

Metadata

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions