paperclipai/paperclip · error · DiscordAdapterCompatibilityError
ensureDiscordRootThread was called for a non-Discord endpoin
Error message
ensureDiscordRootThread was called for a non-Discord endpoint
What it means
ensureDiscordRootThread creates a Discord forum/root thread via the Discord adapter's ensureRootThread extension. Because that capability is Discord-specific, the runtime asserts this.provider === 'discord' first and throws a DiscordAdapterCompatibilityError for any other provider.
Source
Thrown at server/src/services/chat-sdk-runtime.ts:2619
async getUser(user: string | Author): Promise<UserInfo | null> {
return await this.chat.getUser(user);
}
async abortTurn(threadId: string): Promise<void> {
await this.chat.abortTurn(threadId);
}
getProviderAdapter(): Adapter {
return this.adapter;
}
async ensureDiscordRootThread(input: {
channelId: string;
content: string;
messageId: string;
}): Promise<void> {
if (this.provider !== "discord") {
throw new DiscordAdapterCompatibilityError(
"ensureDiscordRootThread was called for a non-Discord endpoint",
);
}
const discord = this.adapter as unknown as DiscordAdapterInternals & {
ensureRootThread?: (
channelId: string,
messageId: string,
content: string,
) => Promise<unknown>;
};
if (typeof discord.ensureRootThread !== "function") {
throw new DiscordAdapterCompatibilityError(
"ensureRootThread is unavailable",
);
}
await discord.ensureRootThread.call(
this.adapter,
input.channelId,View on GitHub (pinned to 01ad858492)
Solutions
- Check runtime provider === 'discord' before calling ensureDiscordRootThread and skip/branch for other providers.
- Fix endpoint configuration or event routing so Discord root-thread bootstrap only runs on Discord endpoints.
- Move the ensure-root-thread step behind a provider dispatch table instead of calling Discord-specific APIs directly.
Example fix
// before
await runtime.ensureDiscordRootThread({ channelId, content, messageId });
// after
if (runtime.provider === "discord") {
await runtime.ensureDiscordRootThread({ channelId, content, messageId });
} Defensive patterns
Strategy: validation
Validate before calling
if (runtime.provider !== "discord") return; // root-thread bootstrap is Discord-only
Type guard
function isDiscordRuntime(r: { provider: string }): boolean { return r.provider === "discord"; } Try / catch
try {
await runtime.ensureDiscordRootThread({ channelId, content, messageId });
} catch (err) {
if (err instanceof DiscordAdapterCompatibilityError && err.message.includes("non-Discord endpoint")) {
// skip bootstrap on non-Discord providers
} else throw err;
} Prevention
- Only call Discord-specific bootstrap from Discord-dispatched code paths.
- Fix event routing so Discord-shaped events never reach non-Discord runtimes.
- Use a provider dispatch table instead of direct Discord API calls in shared flows.
When it happens
Trigger: Calling ensureDiscordRootThread({channelId, content, messageId}) on a runtime bound to a non-Discord provider (telegram, slack, microsoft-teams, etc.).
Common situations: Provider-agnostic bootstrap code that unconditionally ensures a root thread; endpoints reconfigured from Discord to another provider while Discord-specific flows still run; event routing bugs delivering a Discord-shaped event to a non-Discord endpoint.
Understand the failure class
Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.
Related errors
- ensureRootThread is unavailable
- Telegram durable draft transport is unavailable
- file publication receipt capture was called for a non-Slack
- file publication receipt lookup was called for a non-Slack e
- Invalid Discord command owner identifier
AI-assisted analysis of paperclipai/paperclip@01ad858492 (2026-09-10).
Data as JSON: /api/errors/e2ff0b76aa9c2af0.
Report an issue: GitHub.