CRITICAL FIX: Gateway was crashing every 30-50 minutes due to unhandled
fetch() promise rejections causing process termination.
Problem:
- Network fetch() failures (DNS, timeout, connection refused) caused
unhandled promise rejections
- Unhandled rejection handler in src/infra/unhandled-rejections.ts calls
process.exit(1) to prevent silent failures
- Gateway crashed 3 times today (08:12:53, 08:41:31, 09:31:55)
- All agents stopped responding on each crash
- Required manual restart
Root Cause:
- 88+ fetch() calls in codebase without proper error handling
- TypeError: fetch failed at node:internal/deps/undici/undici:15422:13
- No try/catch or .catch() handlers on many network requests
Solution:
- Created safeFetch() wrapper that NEVER throws
- Always resolves to result object (ok: true | false)
- Classifies errors by type (network/abort/timeout/unknown)
- Logs errors with context but keeps gateway running
- Provides convenience helpers: safeFetchText, safeFetchJson
Implementation:
- New file: src/infra/safe-fetch.ts (core wrapper)
- New file: src/infra/safe-fetch.test.ts (comprehensive tests)
- New file: docs/infra/safe-fetch.md (usage guide & migration)
- Modified: src/infra/update-check.ts (example migration)
Testing:
- Full test suite covers success, failures, timeouts, aborts
- Migration verified with update-check.ts as proof of concept
Next Steps:
- Gradually migrate high-risk fetch() calls to safeFetch()
- Priority areas: agents/tools/web-*.ts, providers/*.ts
- Consider making safeFetch the default for new code
This fix prevents immediate crashes but doesn't migrate all calls yet.
Gateway stability should improve significantly with this foundation.