Replace 45 non-null assertions with explicit handling: crash-on-null paths are hidden in compiled code
Labels / Complexity: bug · Medium Complexity — Medium
Problem
The codebase contains 45 non-null assertion operators (!) on values that are not statically guaranteed present (verified with a repository-wide grep). Each one is a runtime undefined/null dereference waiting to happen: the type system is told "trust me", and when the value is absent at runtime the failure is a generic TypeError instead of a typed error, often inside a request handler with no context.
- The failures are silent until they crash. Because
! suppresses the check at compile time, the first signal is a runtime exception in production, not a type error in CI.
- The assertion sites are the risk map. They cluster where the code already doubts its data (conditional access, optional fields, map lookups) — exactly the paths that deserve explicit
if/throw handling with typed errors.
Why this is architecturally hard
- Each site needs a decision. The fix is not a mechanical
! → ? swap: every site must decide between a typed NotFoundException/BadRequestException, a default value, or a genuine invariant (in which case the assertion should be a checked helper, not a bare !).
- The error contract must stay consistent. The repo uses NestJS exceptions; replacing crash sites with the right exception type is part of the fix, and the API error shape must not change for callers.
- Slicing is required. 45 sites span many modules; the migration should land per module so each PR is reviewable and the remaining count is tracked.
Acceptance criteria
- Every non-null assertion is replaced with explicit handling: a typed exception, a default, or a documented checked invariant.
- The repository-wide
! count on non-typed values is zero (or the remaining sites are documented invariants with a checked helper).
npx tsc --noEmit and npm test pass; no behavior change for valid inputs.
Out of scope
The @ts-nocheck migrations (#890 slices); changing API error messages.
Getting started
- Repository-wide:
grep -rn "!" src --include=*.ts to enumerate sites
src/common/ — where a checked invariant helper would live
Commands: npx tsc --noEmit, npm test.
Good first files to read: one module's service with the most assertion sites, then src/common/.
Replace 45 non-null assertions with explicit handling: crash-on-null paths are hidden in compiled code
Labels / Complexity: bug · Medium Complexity — Medium
Problem
The codebase contains 45 non-null assertion operators (
!) on values that are not statically guaranteed present (verified with a repository-wide grep). Each one is a runtimeundefined/nulldereference waiting to happen: the type system is told "trust me", and when the value is absent at runtime the failure is a generic TypeError instead of a typed error, often inside a request handler with no context.!suppresses the check at compile time, the first signal is a runtime exception in production, not a type error in CI.if/throwhandling with typed errors.Why this is architecturally hard
!→?swap: every site must decide between a typedNotFoundException/BadRequestException, a default value, or a genuine invariant (in which case the assertion should be a checked helper, not a bare!).Acceptance criteria
!count on non-typed values is zero (or the remaining sites are documented invariants with a checked helper).npx tsc --noEmitandnpm testpass; no behavior change for valid inputs.Out of scope
The
@ts-nocheckmigrations (#890 slices); changing API error messages.Getting started
grep -rn "!" src --include=*.tsto enumerate sitessrc/common/— where a checked invariant helper would liveCommands:
npx tsc --noEmit,npm test.Good first files to read: one module's service with the most assertion sites, then
src/common/.