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;