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

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