Skip to content

fix(cli): guarantee non-empty [STARTUP] Fatal log on instrumentation-hook boot throw - #10447

Open
diegosouzapw wants to merge 1 commit into
release/v3.8.50from
fix/10171-instrumentation-hook-windows-wsl
Open

fix(cli): guarantee non-empty [STARTUP] Fatal log on instrumentation-hook boot throw#10447
diegosouzapw wants to merge 1 commit into
release/v3.8.50from
fix/10171-instrumentation-hook-windows-wsl

Conversation

@diegosouzapw

Copy link
Copy Markdown
Owner

Summary

Partial diagnostic hardening for #10171 (native Windows / WSL2 boot failure — instrumentation
hook crashes, HTTP listener stays up, every DB-touching route 500s, app.log stays completely
empty). Per the plan-file (_tasks/pipeline/bugs/2-implementing/10171-instrumentation-hook-500-on-windows-wsl.plan.md,
verdict needs-vps), the true root cause on native Windows/WSL2 requires capturing raw child
stderr on a real host — that part is still open and out of scope here.

This PR implements the one safe, narrowly-scoped, testable improvement identified in the plan's
implementation checklist that is independent of the unknown platform-specific root cause:

Confirm #7773 [STARTUP] Fatal log is reached; if not, add a pre-guard (module-load) fatal log
path so app.log is never empty on a failed boot. Add a unit test asserting a boot-instrumentation
failure always yields a non-empty [STARTUP] Fatal: line.

src/instrumentation-node.ts::ensureDbReadyForBoot (#7773/#7828) already prints
[STARTUP] Fatal: Database driver initialization failed: for one specific failure class (DB
driver init), but nothing guaranteed a fatal throw ANYWHERE during instrumentation-hook boot —
including a throw that happens before ensureDbReadyForBoot is even reached (e.g. a module-load
error importing ./instrumentation-node itself) — produces a diagnostic line. 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 to stdout
before rethrowing, so app.log/stdout is never silently empty on a failed boot, regardless of
platform or which step threw.

Explicitly not fixed here (needs the reporter's raw stderr from a real Windows/WSL2 host,
per the plan file):

  • The actual root cause of why the instrumentation hook throws on native Windows / WSL2.
  • Any DB-driver-cascade (better-sqlite3 / node:sqlite / sql.js) fix specific to that platform.

Out of scope, confirmed correct, untouched: needsAndroidCacheDirPrep / isTermux
(bin/cli/utils/ensureAndroidCacheDir.mjs, scripts/build/postinstallSupport.mjs).

Regression test

tests/unit/instrumentation-hook-boot-fatal-log-10171.test.ts — 3 cases:

  1. A boot throw (Error) during instrumentation-hook boot is logged with a non-empty
    [STARTUP] Fatal: line containing the failure message, before rethrow.
  2. A non-Error throw (e.g. bare throw "string", mirroring sql.js's fix(startup): Cannot create property 'message' on string 'Database closed' at registerInstrumentation #6560 pattern) is also
    logged.
  3. A clean successful boot logs nothing.

Fail → pass evidence (ran against the pre-fix register(), then the fixed version):

# unfixed (git show HEAD:src/instrumentation.ts)
✖ #10171: any instrumentation-hook boot throw is logged ... (18620ms, real DB init side effect)
✖ #10171: a non-Error throw during instrumentation-hook boot is still logged ...
✖ register() does not log anything on a clean successful boot
fail 3

# fixed (working tree)
✔ #10171: any instrumentation-hook boot throw is logged ...
✔ #10171: a non-Error throw during instrumentation-hook boot is still logged ...
✔ register() does not log anything on a clean successful boot
pass 3 / fail 0

Gates run

  • npm run typecheck:core — exit 0
  • npx eslint --suppressions-location config/quality/eslint-suppressions.json src/instrumentation.ts tests/unit/instrumentation-hook-boot-fatal-log-10171.test.ts — clean, no output
  • node scripts/check/check-file-size.mjssrc/instrumentation.ts is 42 lines, no new god-file
  • node scripts/check/check-test-discovery.mjs — OK, new test file discovered
  • Complexity/cognitive-complexity ratchet (eslint.complexity-ratchets.config.mjs) scoped to
    src/instrumentation.ts — zero violations
  • node --import tsx/esm --test tests/unit/instrumentation-hook-boot-fatal-log-10171.test.ts — 3/3 pass

Refs #10171 (not Closes — this is a partial diagnostic hardening; the platform-specific root
cause still needs a real Windows/WSL2 host's raw child stderr per the plan file, tracked as
hold-vps).

⚠️ base-red inherited: #9985 — ESLint errors (2) from #10250 (i18n PT-PT translation), unrelated
to this change.

…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).
@diegosouzapw diegosouzapw added the hold-vps PR verde, merge aguardando validação live (release-drain) label Aug 15, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

hold-vps PR verde, merge aguardando validação live (release-drain)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants