Files
OmniRoute/src/lib/instrumentationBootError.ts
Diego Rodrigues de Sa e Souza 6d99a46d4b fix(cli): guarantee non-empty [STARTUP] Fatal log on instrumentation-hook boot throw (#10447)
* fix(cli): guarantee non-empty [STARTUP] Fatal log on instrumentation-hook boot throw

Refs #10171: on native Windows / WSL2 boots, an instrumentation-hook throw
during module-load or registerNodejs() leaves the HTTP listener up while
every DB-touching route 500s, with app.log staying completely empty. The
#7773/#7828 guard in ensureDbReadyForBoot only logs one specific failure
class (DB driver init). register() in src/instrumentation.ts now wraps the
boot call in a try/catch at the outermost boundary and unconditionally logs
a "[STARTUP] Fatal: instrumentation hook failed during boot:" line before
rethrowing, so app.log/stdout is never silently empty on a failed boot
regardless of platform or which step threw.

This is a partial diagnostic hardening, not the full fix for #10171 — the
platform-specific root cause on native Windows/WSL2 still needs the
reporter's raw child stderr from a real host (tracked separately, see
_tasks/pipeline/bugs/2-implementing/10171-instrumentation-hook-500-on-windows-wsl.plan.md).

* fix(cli): normalize instrumentation boot errors

Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>

* fix(cli): reuse shared normalizeBootError helper in instrumentation.ts

The outermost instrumentation-hook boot boundary (#10171) was inlining its
own err-instanceof-Error normalization instead of reusing the existing
normalizeBootError() helper already defined in instrumentation-node.ts for
the same purpose (#6560/#7773). Extract it into a dependency-free
src/lib/instrumentationBootError.ts so both instrumentation.ts (which also
loads under the Edge runtime) and instrumentation-node.ts can import it
statically without risking a second failing dynamic import of
instrumentation-node.ts from within the catch block.

---------

Co-authored-by: adevwithpurpose <adevwithpurpose@users.noreply.github.com>
2026-08-18 10:57:44 -03:00

27 lines
1.4 KiB
TypeScript

/**
* Normalize any thrown/rejected value into a real `Error` instance.
*
* Next.js's own `registerInstrumentation()` wrapper (see
* `node_modules/next/dist/server/lib/router-utils/instrumentation-globals.external.js`)
* unconditionally does `err.message = \`...${err.message}\`` on whatever our
* `register()` export (`src/instrumentation.ts`) rejects with, assuming it is
* always an `Error`. If a raw non-Error primitive bubbles up instead (e.g.
* sql.js's WASM adapter throws the bare string `"Database closed"` — see
* `./db/adapters/sqljsAdapter.ts`), that assignment throws `TypeError: Cannot
* create property 'message' on string '...'` in strict mode, masking the
* original error and crashing the whole server on every boot (#6560).
* Normalizing before it leaves our code guarantees Next always receives
* something `.message`-assignable.
*
* Deliberately dependency-free (no imports) so both `src/instrumentation.ts`
* (the shared Edge+Node instrumentation entry point) and
* `src/instrumentation-node.ts` (the Node-only boot sequence) can import it
* statically without pulling Node-specific modules (fs/path/os/better-sqlite3
* etc.) into the Edge runtime bundle, and without relying on a dynamic
* `import("./instrumentation-node")` that could itself be the thing that
* failed to load (#10171).
*/
export function normalizeBootError(err: unknown): Error {
return err instanceof Error ? err : new Error(String(err));
}