Skip to content

fix: log the cause of a fatal error instead of dropping it - #31

Merged
DamengRandom merged 1 commit into
masterfrom
fix/scan-fatal-error-dropped
Aug 1, 2026
Merged

fix: log the cause of a fatal error instead of dropping it#31
DamengRandom merged 1 commit into
masterfrom
fix/scan-fatal-error-dropped

Conversation

@DamengRandom

Copy link
Copy Markdown
Owner

Closes #30

The change

src/index.ts:48 passed the error as pino's second positional argument. Pino reads a leading string as a printf format string, so err was consumed as an interpolation value for a placeholder that does not exist and never reached the log — every crash of every job printed Fatal system error ⚠️❌⚠️❌: and nothing else.

-  logger.error('Fatal system error ⚠️❌⚠️❌: ', err)
+  logger.error({ err }, 'Fatal system error ⚠️❌⚠️❌')

This is the form already used at every other error call site in the repo. It was the only outlier.

The test

src/fatal-error.test.ts spawns the real CLI with DATABASE_URL pointed at a closed port, so initDb() rejects and main()'s catch handler runs for real, then asserts the cause survives into the output. No database, network or credentials needed — port 1 on loopback refuses immediately.

Verified it fails on the unfixed tree and passes on the fixed one:

### WITHOUT fix:
# pass 0
# fail 1
### WITH fix:
# pass 1
# fail 0

Checks

# tests 76
# pass 76
# fail 0

pnpm tsc and pnpm format:check both clean.

Observed vs reasoned

Observed by execution: the pino drop, with both call forms run against the same Error object in one process — one printed type, message and full stack, the other printed nothing. The end-to-end CLI run producing the bare line and exit code 1. The identity of the discarded error (Error: connect ECONNREFUSED). The test failing before the change and passing after. The full suite, tsc and format:check after the change.

Reasoned, not executed: that the same handler also swallows a createLlm() failure thrown out of runDailyJobs — that path needs an interactive daily-kpi run this scan could not perform. The fix does not depend on it; the initDb() path is covered by the test.

🤖 Generated with Claude Code

https://claude.ai/code/session_01YA7F47ZTqxswS4qy34VNdG


Generated by Claude Code

Pino reads a leading string as a printf format string, so the error was
consumed as an interpolation value for a placeholder that does not exist
and never reached the log.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YA7F47ZTqxswS4qy34VNdG
@DamengRandom
DamengRandom marked this pull request as ready for review August 1, 2026 12:12
@DamengRandom
DamengRandom merged commit d19230b into master Aug 1, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

The top-level fatal handler discards the error — every crash logs a bare prefix and nothing else

2 participants