diff --git a/src/gateway/server.impl.ts b/src/gateway/server.impl.ts index efa91be76..a793966b6 100644 --- a/src/gateway/server.impl.ts +++ b/src/gateway/server.impl.ts @@ -148,6 +148,19 @@ export async function startGatewayServer( port = 18789, opts: GatewayServerOptions = {}, ): Promise { + // Install global unhandled rejection handler to prevent gateway crashes + // from background promises (e.g., Telegram polling, network operations) + const handleUnhandledRejection = (reason: unknown, promise: Promise) => { + const formatted = reason instanceof Error ? reason.message : String(reason); + log.error(`unhandled promise rejection: ${formatted}`); + // Log additional details for debugging + if (reason instanceof Error && reason.stack) { + log.debug(`rejection stack: ${reason.stack}`); + } + // Don't crash the gateway - log and continue + }; + process.on("unhandledRejection", handleUnhandledRejection); + // Ensure all default port derivations (browser/canvas) see the actual runtime port. process.env.OPENCLAW_GATEWAY_PORT = String(port); logAcceptedEnvOption({ @@ -572,6 +585,9 @@ export async function startGatewayServer( return { close: async (opts) => { + // Remove unhandled rejection handler on shutdown + process.off("unhandledRejection", handleUnhandledRejection); + if (diagnosticsEnabled) { stopDiagnosticHeartbeat(); } diff --git a/src/telegram/monitor.ts b/src/telegram/monitor.ts index 2709b591b..17ea74a18 100644 --- a/src/telegram/monitor.ts +++ b/src/telegram/monitor.ts @@ -161,7 +161,12 @@ export async function monitorTelegramProvider(opts: MonitorTelegramOpts = {}) { const runner = run(bot, createTelegramRunnerOptions(cfg)); const stopOnAbort = () => { if (opts.abortSignal?.aborted) { - void runner.stop(); + // Properly await runner.stop() to prevent unhandled rejections + runner.stop().catch((err) => { + (opts.runtime?.error ?? console.error)( + `telegram: runner stop failed: ${formatErrorMessage(err)}`, + ); + }); } }; opts.abortSignal?.addEventListener("abort", stopOnAbort, { once: true }); @@ -194,6 +199,13 @@ export async function monitorTelegramProvider(opts: MonitorTelegramOpts = {}) { } } finally { opts.abortSignal?.removeEventListener("abort", stopOnAbort); + // Ensure runner is stopped to prevent lingering promises + try { + await runner.stop(); + } catch (stopErr) { + // Suppress errors from runner.stop() in finally block + // (already logged by stopOnAbort if abort-triggered) + } } } }