Add top-level unhandledRejection/uncaughtException handlers #101

Closed
opened 2026-07-15 19:51:33 +00:00 by claude-bot · 1 comment
Contributor

Severity: Low · Confidence: High · Effort: XS · Category: ops

Evidence

  • api/src/index.ts - no process-level handlers registered. Fire-and-forget promises exist (entries.ts:265,403-404; media.ts:87; reanalyzeWorker.ts:70), all currently .catch()'d.

Problem
Node 24 terminates the process on an unhandled rejection. Every current fire-and-forget is guarded, but one future unguarded rejection would hard-crash the process - which also kills all in-process workers.

Impact
A single missed .catch becomes a full outage rather than a logged error. Low today; cheap insurance.

Fix
Register top-level unhandledRejection/uncaughtException handlers that log with context and (ideally) hook the graceful-shutdown path from F-08.

Acceptance criteria

  • An unhandled rejection is logged with a stack instead of silently crashing.

Related: F-08 (graceful shutdown).


Filed from the 2026-07-15 codebase audit. Full report: docs/.internal/report-2026-07-15.md (gitignored).

**Severity:** Low · **Confidence:** High · **Effort:** XS · Category: ops **Evidence** - `api/src/index.ts` - no process-level handlers registered. Fire-and-forget promises exist (entries.ts:265,403-404; media.ts:87; reanalyzeWorker.ts:70), all currently `.catch()`'d. **Problem** Node 24 terminates the process on an unhandled rejection. Every current fire-and-forget is guarded, but one future unguarded rejection would hard-crash the process - which also kills all in-process workers. **Impact** A single missed `.catch` becomes a full outage rather than a logged error. Low today; cheap insurance. **Fix** Register top-level `unhandledRejection`/`uncaughtException` handlers that log with context and (ideally) hook the graceful-shutdown path from F-08. **Acceptance criteria** - [ ] An unhandled rejection is logged with a stack instead of silently crashing. Related: F-08 (graceful shutdown). --- _Filed from the 2026-07-15 codebase audit. Full report: `docs/.internal/report-2026-07-15.md` (gitignored)._
Author
Contributor

Fixed in c1ed843 (v7.2.0 wave 2).

Registered in api/src/index.ts, hooked into the #85 graceful-shutdown path as suggested:

  • unhandledRejection → log with the stack and keep serving. A stray rejection in a background job shouldn't take down the API and every in-process worker with it; the point is that it's diagnosable instead of a silent exit.
  • uncaughtException → log, then drain through shutdown() and exit non-zero. Unlike a rejection this leaves the process in an undefined state, so restarting clean (via restart: unless-stopped) is right.

This required a small change to shutdown(): it always called process.exit(0), so routing a crash through it would have reported an abnormal termination as a clean exit — hiding crashes from the container runtime and any future alerting. It now takes an exit code (default 0 for SIGTERM/SIGINT, 1 for a crash).

Acceptance criteria:

  • An unhandled rejection is logged with a stack instead of silently crashing.

CI green (242/242).

Fixed in `c1ed843` (v7.2.0 wave 2). Registered in `api/src/index.ts`, hooked into the #85 graceful-shutdown path as suggested: - **`unhandledRejection`** → log with the stack and **keep serving**. A stray rejection in a background job shouldn't take down the API and every in-process worker with it; the point is that it's diagnosable instead of a silent exit. - **`uncaughtException`** → log, then drain through `shutdown()` and exit **non-zero**. Unlike a rejection this leaves the process in an undefined state, so restarting clean (via `restart: unless-stopped`) is right. This required a small change to `shutdown()`: it always called `process.exit(0)`, so routing a crash through it would have reported an abnormal termination as a **clean exit** — hiding crashes from the container runtime and any future alerting. It now takes an exit code (default 0 for SIGTERM/SIGINT, 1 for a crash). **Acceptance criteria:** - [x] An unhandled rejection is logged with a stack instead of silently crashing. CI green (242/242).
Sign in to join this conversation.
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
rbrooks/TeaLeaves#101
No description provided.