From 8419675fa160460f62753cec5eaaa81ee93c0ff3 Mon Sep 17 00:00:00 2001 From: moguangyu5-design Date: Tue, 14 Jul 2026 12:45:57 +0800 Subject: [PATCH] fix(session): swallow onRecordError throw to avoid unhandled rejection (#106951) * fix(session): swallow onRecordError throw to avoid unhandled rejection * fix(session): settle async record error handlers * fix(session): assimilate record handler results --------- Co-authored-by: moguangyu5-design Co-authored-by: Peter Steinberger --- src/channels/session.test.ts | 35 +++++++++++++++++++++++++++++++++++ src/channels/session.ts | 8 +++++++- 2 files changed, 42 insertions(+), 1 deletion(-) diff --git a/src/channels/session.test.ts b/src/channels/session.test.ts index cdb239680e1f..3bfed7d45e60 100644 --- a/src/channels/session.test.ts +++ b/src/channels/session.test.ts @@ -189,4 +189,39 @@ describe("recordInboundSession", () => { expect(route.sessionKey).toBe("agent:main:main"); expect(route.createIfMissing).toBe(false); }); + + it.each([ + { + name: "throws synchronously", + handler: (_err: unknown): void => { + throw new Error("handler failed"); + }, + }, + { + name: "returns a rejected promise", + handler: ((_err: unknown) => Promise.reject(new Error("handler failed"))) as ( + _err: unknown, + ) => void, + }, + ])("settles the tracked meta task when onRecordError $name", async ({ handler }) => { + const recordError = new Error("db failed"); + recordSessionMetaFromInboundMock.mockRejectedValueOnce(recordError); + const onRecordError = vi.fn(handler); + let trackedMetaTask: Promise | undefined; + + await recordInboundSession({ + storePath: "/tmp/openclaw-session-store.json", + sessionKey: "agent:main:demo-channel:1234:thread:42", + ctx, + onRecordError, + trackSessionMetaTask: (task) => { + trackedMetaTask = task; + }, + }); + + expect(trackedMetaTask).toBeDefined(); + await expect(trackedMetaTask).resolves.toBeUndefined(); + expect(onRecordError).toHaveBeenCalledTimes(1); + expect(onRecordError).toHaveBeenCalledWith(recordError); + }); }); diff --git a/src/channels/session.ts b/src/channels/session.ts index a1e58333e4d8..381d5dd59a5e 100644 --- a/src/channels/session.ts +++ b/src/channels/session.ts @@ -48,7 +48,13 @@ export async function recordInboundSession(params: { groupResolution, createIfMissing, }) - .catch(params.onRecordError); + .catch(async (err: unknown) => { + try { + await Promise.resolve(params.onRecordError(err)); + } catch { + // Error reporting must not reject the detached metadata task. + } + }); params.trackSessionMetaTask?.(metaTask); void metaTask;