fix(server): serialize startup error so docker logs are debuggable#843
Conversation
Top-level `main().catch` was logging `{ error }` directly, and
`JSON.stringify(new Error())` returns `{}` because Error's own
properties are non-enumerable. Docker users saw
{"level":"error","msg":"Failed to start server","error":{}}
with zero signal about which env var or config field was the cause
(issue #766).
Walk the error manually (type / message / stack / code / ZodError
issues / AggregateError children / cause chain) before logging,
and also write a plain-text "Failed to start server: <type>: <msg>"
line to stderr as a fallback for any log shipper that drops the
structured fields.
Fixes #766
|
Caution Review failedThe pull request is closed. ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (1)
📝 WalkthroughWalkthroughThis PR adds a ChangesBoot Error Serialization
Estimated code review effort🎯 2 (Simple) | ⏱️ ~10 minutes Poem
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Warning There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure. 🔧 ESLint
ESLint skipped: no ESLint configuration detected in root package.json. To enable, add Comment |
|
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
External user (#766) tried docker-compose against the published ghcr.io/lobu-ai/lobu-app image, missing required env (ENCRYPTION_KEY, BETTER_AUTH_SECRET) and unable to debug because the boot error logged as empty `{}`. PR #843 fixed the error logging. This commit fills the remaining gap: a working sample compose, a self-hosting doc that spells out what's actually required vs optional, and a .env.example that no longer claims ANTHROPIC_API_KEY is required. Image itself is unchanged (already generic enough). Documents the provider-agnostic reality: 17 providers in config/providers.json, no env-var required at boot for any of them, runtime provisioning via admin UI works fine. Refs #766.
Summary
Top-level
main().catchinpackages/server/src/server.tslogged the boot error directly withlogger.error({ error }, 'Failed to start server'). When the pinoerrorserializer isn't picked up (older image, bundler tree-shake, or before #767 landed in a given build), pino falls back to plain object serialization — andJSON.stringify(new Error('boom'))returns{}becauseErrorproperties are non-enumerable.Docker users (issue #766) saw exactly this and had zero signal about which env var or config field was wrong:
This PR adds a small
serializeBootError(err)walker right at the catch site that pulls out:type(constructor name)messagestackcode(if present, e.g. ECONNREFUSED)issues(ZodError field-path array)errors(AggregateError children, recursively)cause(recursively)…and logs the result under both
err(pino convention) anderror(legacy key) so the line is informative regardless of pino config. As a last-resort fallback it also writes a plain-textFailed to start server: <Type>: <message>+ stack to stderr, so users whose log shipper only captures stderr or strips structured fields still see the cause.Reproducer
Pre-fix behavior (what #766 hits):
Post-fix behavior (same scenario after
serializeBootError):The original
error: {}line is replaced by a fully-structured object withtype/message/stack, plus a stderr fallback fordocker logsconsumers.Test plan
bunx tsc --noEmit -p packages/server/tsconfig.jsoncleandotenv.config()returning empty +DATABASE_URLset + noENCRYPTION_KEY. Pre-fix printserror:{}; post-fix prints full message + stack + stderr fallback line.Fixes #766
Summary by CodeRabbit