Discord: handle gateway 4014 close

This commit is contained in:
Shadow
2026-02-19 13:47:28 -06:00
parent 85fee30e6b
commit f7a8c2df2c
2 changed files with 30 additions and 2 deletions

View File

@@ -8,6 +8,7 @@ Docs: https://docs.openclaw.ai
### Fixes
- Discord/Gateway: handle close code 4014 (missing privileged gateway intents) without crashing the gateway. Thanks @thewilloftheshadow.
- Security/Net: strip sensitive headers (`Authorization`, `Proxy-Authorization`, `Cookie`, `Cookie2`) on cross-origin redirects in `fetchWithSsrFGuard` to prevent credential forwarding across origin boundaries. (#20313) Thanks @afurm.
- Auto-reply/Runner: emit `onAgentRunStart` only after agent lifecycle or tool activity begins (and only once per run), so fallback preflight errors no longer mark runs as started. (#21165) Thanks @shakkernerd.
- Auto-reply/Prompt caching: restore prefix-cache stability by keeping inbound system metadata session-stable and moving per-message IDs (`message_id`, `message_id_full`, `reply_to_id`, `sender_id`) into untrusted conversation context. (#20597) Thanks @anisoptera.

View File

@@ -5,7 +5,7 @@ import {
type BaseMessageInteractiveComponent,
type Modal,
} from "@buape/carbon";
import type { GatewayPlugin } from "@buape/carbon/gateway";
import { GatewayCloseCodes, type GatewayPlugin } from "@buape/carbon/gateway";
import { Routes } from "discord-api-types/v10";
import { resolveTextChunkLimit } from "../../auto-reply/chunk.js";
import { listNativeCommandSpecsForConfig } from "../../auto-reply/commands-registry.js";
@@ -167,6 +167,16 @@ function formatDiscordDeployErrorDetails(err: unknown): string {
return details.length > 0 ? ` (${details.join(", ")})` : "";
}
const DISCORD_DISALLOWED_INTENTS_CODE = GatewayCloseCodes.DisallowedIntents;
function isDiscordDisallowedIntentsError(err: unknown): boolean {
if (!err) {
return false;
}
const message = formatErrorMessage(err);
return message.includes(String(DISCORD_DISALLOWED_INTENTS_CODE));
}
export async function monitorDiscordProvider(opts: MonitorDiscordOpts = {}) {
const cfg = opts.config ?? loadConfig();
const account = resolveDiscordAccount({
@@ -643,6 +653,8 @@ export async function monitorDiscordProvider(opts: MonitorDiscordOpts = {}) {
}, HELLO_TIMEOUT_MS);
};
gatewayEmitter?.on("debug", onGatewayDebug);
// Disallowed intents (4014) should stop the provider without crashing the gateway.
let sawDisallowedIntents = false;
try {
await waitForDiscordGatewayStop({
gateway: gateway
@@ -653,15 +665,30 @@ export async function monitorDiscordProvider(opts: MonitorDiscordOpts = {}) {
: undefined,
abortSignal,
onGatewayError: (err) => {
if (isDiscordDisallowedIntentsError(err)) {
sawDisallowedIntents = true;
runtime.error?.(
danger(
"discord: gateway closed with code 4014 (missing privileged gateway intents). Enable the required intents in the Discord Developer Portal or disable them in config.",
),
);
return;
}
runtime.error?.(danger(`discord gateway error: ${String(err)}`));
},
shouldStopOnError: (err) => {
const message = String(err);
return (
message.includes("Max reconnect attempts") || message.includes("Fatal Gateway error")
message.includes("Max reconnect attempts") ||
message.includes("Fatal Gateway error") ||
isDiscordDisallowedIntentsError(err)
);
},
});
} catch (err) {
if (!sawDisallowedIntents && !isDiscordDisallowedIntentsError(err)) {
throw err;
}
} finally {
unregisterGateway(account.accountId);
stopGatewayLogging();