From 8a8a12559df022e1061639925c25572679d845e0 Mon Sep 17 00:00:00 2001 From: Vincent Koc Date: Sun, 3 May 2026 23:54:58 -0700 Subject: [PATCH] fix(discord): clear failed startup probe status --- CHANGELOG.md | 1 + extensions/discord/src/channel.test.ts | 32 ++++++++++++++++++++++++++ extensions/discord/src/channel.ts | 7 ++++++ 3 files changed, 40 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4dc781e25f7..fac779a9f31 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -56,6 +56,7 @@ Docs: https://docs.openclaw.ai ### Fixes +- Discord: clear stale startup probe bot/application status when the async bot probe throws, not just when it returns a degraded probe result. Thanks @vincentkoc. - Web search: scope explicit bundled `web_search` provider runtime loading through manifest ownership, so selecting DuckDuckGo/Gemini/etc. does not import unrelated bundled providers or log their optional dependency failures. Thanks @vincentkoc. - Release/beta smoke: resolve the dispatched Telegram beta E2E run from `gh run list` when `gh workflow run` returns no run URL, so the maintainer helper does not fail immediately after dispatch. Thanks @vincentkoc. - Media/images: keep HEIC/HEIF attachments fail-closed when optional Sharp conversion is unavailable instead of sending originals that still need conversion. Thanks @vincentkoc. diff --git a/extensions/discord/src/channel.test.ts b/extensions/discord/src/channel.test.ts index f07cf74cc12..92a14e3416f 100644 --- a/extensions/discord/src/channel.test.ts +++ b/extensions/discord/src/channel.test.ts @@ -515,6 +515,38 @@ describe("discordPlugin outbound", () => { ); }); + it("clears stale Discord probe metadata when the async startup probe throws", async () => { + probeDiscordMock.mockRejectedValue(new Error("probe timed out")); + monitorDiscordProviderMock.mockResolvedValue(undefined); + + const cfg = createCfg(); + const statusPatches: Array> = []; + const ctx = createStartAccountContext({ + account: resolveAccount(cfg), + cfg, + statusPatchSink: (next) => statusPatches.push({ ...next }), + }); + ctx.setStatus({ + accountId: "default", + bot: { username: "OldBot" }, + application: { intents: { messageContent: "enabled" } }, + }); + + await discordPlugin.gateway!.startAccount!(ctx); + + await vi.waitFor(() => + expect( + statusPatches.some( + (patch) => + "bot" in patch && + "application" in patch && + patch.bot === undefined && + patch.application === undefined, + ), + ).toBe(true), + ); + }); + it("stagger starts later accounts in multi-bot setups", async () => { probeDiscordMock.mockResolvedValue({ ok: true, diff --git a/extensions/discord/src/channel.ts b/extensions/discord/src/channel.ts index 48a6e14632c..682d8350e49 100644 --- a/extensions/discord/src/channel.ts +++ b/extensions/discord/src/channel.ts @@ -130,6 +130,13 @@ function startDiscordStartupProbe(params: { ); } } catch (err) { + if (!params.abortSignal.aborted) { + params.setStatus({ + accountId: params.accountId, + bot: undefined, + application: undefined, + }); + } if (getDiscordRuntime().logging.shouldLogVerbose()) { params.log?.debug?.(`[${params.accountId}] bot probe failed: ${String(err)}`); }