diff --git a/openclaw b/openclaw new file mode 160000 index 000000000..0639c7bf1 --- /dev/null +++ b/openclaw @@ -0,0 +1 @@ +Subproject commit 0639c7bf1f37bafeb847afc9e422f05f3bb084a3 diff --git a/src/commands/onboard-auth.credentials.ts b/src/commands/onboard-auth.credentials.ts index fbf6dbfb9..08dba7fee 100644 --- a/src/commands/onboard-auth.credentials.ts +++ b/src/commands/onboard-auth.credentials.ts @@ -10,8 +10,9 @@ export async function writeOAuthCredentials( agentDir?: string, ): Promise { // Write to resolved agent dir so gateway finds credentials on startup. + const emailStr = typeof creds.email === "string" ? creds.email : "default"; upsertAuthProfile({ - profileId: `${provider}:${creds.email ?? "default"}`, + profileId: `${provider}:${emailStr}`, credential: { type: "oauth", provider, diff --git a/src/gateway/server.impl.ts b/src/gateway/server.impl.ts index efa91be76..5e8d2ae97 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..abb52ce31 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 { + // Suppress errors from runner.stop() in finally block + // (already logged by stopOnAbort if abort-triggered) + } } } }