From a0ab301dc31cbb4efb92ff8d831533d3c05e4a8d Mon Sep 17 00:00:00 2001 From: Rain Date: Mon, 16 Feb 2026 21:00:30 +0800 Subject: [PATCH] Fix Discord auto-thread attempting to thread in Forum/Media channels\n\nCreating threads on messages within Forum/Media channels is often redundant\nor invalid (as messages are already posts). This prevents API errors and spam.\n\nFix: Check channel type before attempting auto-thread creation. --- .../monitor/message-handler.process.ts | 1 + .../monitor/threading.auto-thread.test.ts | 54 +++++++++++++++++++ src/discord/monitor/threading.ts | 13 +++++ 3 files changed, 68 insertions(+) create mode 100644 src/discord/monitor/threading.auto-thread.test.ts diff --git a/src/discord/monitor/message-handler.process.ts b/src/discord/monitor/message-handler.process.ts index 14616420f4..16e0af4da4 100644 --- a/src/discord/monitor/message-handler.process.ts +++ b/src/discord/monitor/message-handler.process.ts @@ -483,6 +483,7 @@ export async function processDiscordMessage(ctx: DiscordMessagePreflightContext) isGuildMessage, channelConfig, threadChannel, + channelType: channelInfo?.type, baseText: baseText ?? "", combinedBody, replyToMode, diff --git a/src/discord/monitor/threading.auto-thread.test.ts b/src/discord/monitor/threading.auto-thread.test.ts new file mode 100644 index 0000000000..176a99248c --- /dev/null +++ b/src/discord/monitor/threading.auto-thread.test.ts @@ -0,0 +1,54 @@ +import { describe, it, expect, vi } from "vitest"; +import { ChannelType } from "@buape/carbon"; +import { maybeCreateDiscordAutoThread } from "./threading.js"; + +describe("maybeCreateDiscordAutoThread", () => { + const mockClient = { rest: { post: vi.fn(), get: vi.fn() } } as any; + const mockMessage = { id: "msg1", timestamp: "123" } as any; + + it("skips auto-thread if channelType is GuildForum", async () => { + const result = await maybeCreateDiscordAutoThread({ + client: mockClient, + message: mockMessage, + messageChannelId: "forum1", + isGuildMessage: true, + channelConfig: { autoThread: true }, + channelType: ChannelType.GuildForum, + baseText: "test", + combinedBody: "test", + }); + expect(result).toBeUndefined(); + expect(mockClient.rest.post).not.toHaveBeenCalled(); + }); + + it("skips auto-thread if channelType is GuildMedia", async () => { + const result = await maybeCreateDiscordAutoThread({ + client: mockClient, + message: mockMessage, + messageChannelId: "media1", + isGuildMessage: true, + channelConfig: { autoThread: true }, + channelType: ChannelType.GuildMedia, + baseText: "test", + combinedBody: "test", + }); + expect(result).toBeUndefined(); + expect(mockClient.rest.post).not.toHaveBeenCalled(); + }); + + it("creates auto-thread if channelType is GuildText", async () => { + mockClient.rest.post.mockResolvedValueOnce({ id: "thread1" }); + const result = await maybeCreateDiscordAutoThread({ + client: mockClient, + message: mockMessage, + messageChannelId: "text1", + isGuildMessage: true, + channelConfig: { autoThread: true }, + channelType: ChannelType.GuildText, + baseText: "test", + combinedBody: "test", + }); + expect(result).toBe("thread1"); + expect(mockClient.rest.post).toHaveBeenCalled(); + }); +}); diff --git a/src/discord/monitor/threading.ts b/src/discord/monitor/threading.ts index 718f1d11da..d5a5875fbd 100644 --- a/src/discord/monitor/threading.ts +++ b/src/discord/monitor/threading.ts @@ -298,6 +298,7 @@ export async function resolveDiscordAutoThreadReplyPlan(params: { isGuildMessage: boolean; channelConfig?: DiscordChannelConfigResolved | null; threadChannel?: DiscordThreadChannel | null; + channelType?: ChannelType; baseText: string; combinedBody: string; replyToMode: ReplyToMode; @@ -320,6 +321,7 @@ export async function resolveDiscordAutoThreadReplyPlan(params: { isGuildMessage: params.isGuildMessage, channelConfig: params.channelConfig, threadChannel: params.threadChannel, + channelType: params.channelType, baseText: params.baseText, combinedBody: params.combinedBody, }); @@ -348,6 +350,7 @@ export async function maybeCreateDiscordAutoThread(params: { isGuildMessage: boolean; channelConfig?: DiscordChannelConfigResolved | null; threadChannel?: DiscordThreadChannel | null; + channelType?: ChannelType; baseText: string; combinedBody: string; }): Promise { @@ -360,6 +363,16 @@ export async function maybeCreateDiscordAutoThread(params: { if (params.threadChannel) { return undefined; } + // Avoid creating threads in channels that don't support it or are already forums + if ( + params.channelType === ChannelType.GuildForum || + params.channelType === ChannelType.GuildMedia || + params.channelType === ChannelType.GuildVoice || + params.channelType === ChannelType.GuildStageVoice + ) { + return undefined; + } + const messageChannelId = ( params.messageChannelId || resolveDiscordMessageChannelId({