#Bug: Discord plugin connects but never processes inbound MESSAGE_CREATE events

1 messages · Page 1 of 1 (latest)

rough jewel
#

O plugin conecta ao Discord Gateway, resolve canais via REST, mas nunca processa eventos inbound (MESSAGE_CREATE). O runtime.connected nunca Ă© setado para true, fazendo o health-monitor reportar "disconnected" a cada 5 minutos.

Prova: Conectando manualmente com o mesmo token ao WebSocket do Discord, MESSAGE_CREATE Ă© recebido normalmente. O problema Ă© exclusivo do plugin OpenClaw.

Reproduzido em: 2026.3.11 e 2026.3.12
Causa provável: runtime.connected nunca muda de false para true após o evento READY do discord.js

#

@hardy moon

#

Bug: Discord plugin connects but never processes inbound MESSAGE_CREATE events

O plugin conecta ao Discord Gateway, resolve canais via REST, mas nunca processa eventos inbound (MESSAGE_CREATE). O runtime.connected nunca Ă© setado para true, fazendo o health-monitor reportar "disconnected" a cada 5 minutos.

Prova: Conectando manualmente com o mesmo token ao WebSocket do Discord, MESSAGE_CREATE Ă© recebido normalmente. O problema Ă© exclusivo do plugin OpenClaw.

Reproduzido em: 2026.3.11 e 2026.3.12
Causa provável: runtime.connected nunca muda de false para true após o evento READY do discord.js

@hardy moon

hardy moonBOT
#

Isso aí não é discord.js no OpenClaw — o Discord monitor usa @buape/carbon. E no Carbon o gateway.isConnected só vira true depois de READY/RESUMED. Então se o runtime.connected nunca muda, o mais provável é: READY nunca está chegando (ou o gateway está sendo fechado antes disso).

O caso mais comum que bate exatamente com esse sintoma (conecta “no TCP/WS”, REST funciona, mas nunca fica “connected” e não chega MESSAGE_CREATE) é close code 4014 (Disallowed Intents):

  • O OpenClaw sempre solicita MessageContent intent (privilegiado).
  • Se o bot nĂŁo tiver “Message Content Intent” habilitado no Developer Portal, o Discord fecha a sessĂŁo do gateway com 4014, e vocĂŞ nunca vai ter READY → nunca processa inbound.

O seu teste “manual” no websocket pode estar usando intents = 0 (ou sem MessageContent), e aí você ainda consegue ver MESSAGE_CREATE (talvez sem content), o que dá a impressão que “o token funciona”.

O que eu checaria agora

  1. Discord Developer Portal → Application → Bot → Privileged Gateway Intents

    • habilitar Message Content Intent (e reinvitar o bot se necessário)
    • (Server Members / Presence sĂł se vocĂŞ realmente usa essas features)
  2. Logs do OpenClaw: procura algo como:

    • WebSocket connection closed with code 4014
    • Fatal Gateway error: 4014
#
  • ou qualquer “closed with code …” logo apĂłs “connection opened”

Docs (passo de intents): https://docs.openclaw.ai/channels/discord

Se você já tem o Message Content Intent habilitado e mesmo assim não chega READY, cola aqui um trecho curto dos logs (sem token) com as linhas do “discord:” desde o start até a primeira desconexão — aí dá pra cravar se é 4014/invalid session/sharding/etc.

rough jewel
#

Bug: Discord plugin connects but never processes inbound MESSAGE_CREATE events
Environment
OpenClaw version: 2026.3.12 (also reproduced on 2026.3.11)
OS: Linux 6.8.0-101-generic (x64) · Node 25.8.1
Container: Docker (512MB RAM, 1 CPU)
Discord.js: Bundled with OpenClaw (via plugin-sdk)
Bot: 1 guild, 7 channels allowed
Config
json5
channels: {
discord: {
enabled: true,
token: "...",
groupPolicy: "allowlist",
streaming: "off",
dmPolicy: "open",
allowFrom: [""],
intents: { presence: true, guildMembers: true },
guilds: {
"<GUILD_ID>": {
requireMention: true,
users: ["<USER_ID>"],
channels: { /
7 channels with allow: true */ }
}
}
}
}
Symptoms
Discord plugin starts, logs starting provider (@BotName)
Channels resolve successfully via REST API
No MESSAGE_CREATE events are ever processed — mentions go unanswered
Health-monitor reports disconnected after exactly 300s (5-minute check interval)
Health-monitor restart attempt fails silently — no reconnection occurs
Outbound REST API works perfectly (bot can send messages, read channels, react)
Evidence
Raw WebSocket test (WORKS)
Connected directly to wss://gateway.discord.gg/?v=10&encoding=json with the same bot token:

Received HELLO, sent IDENTIFY with intents 38791
Received READY + GUILD_CREATE
Received MESSAGE_CREATE when user sent @Bot teste
Connection stayed alive for 5.5+ minutes (331s, 8 heartbeat cycles)
OpenClaw Discord plugin (FAILS)
Logs show "channels resolved" but ZERO inbound message processing
Even messages sent within 30 seconds of startup are not received
runtime.connected appears to never be set to true
Health-monitor detects snapshot.connected === false at 300s check
Timeline pattern (consistent across every restart)

T+0s → "starting provider (@Bot)"
T+2s → "discord channels resolved" (REST API)
T+2s → "discord channel users resolved"
T+10s → User sends @mention — NOT RECEIVED
T+300s → "health-monitor: restarting (reason: disconnected)"
T+300s+ → Restart fails silently, no reconnection
Capabilities output

Intents: messageContent=limited guildMembers=limited presence=limited
All three privileged intents enabled in Developer Portal + OpenClaw config.

Bot permissions
Bot has ADMINISTRATOR role in the guild
REST API read/write works for all configured channels
Analysis
The issue appears to be in the OpenClaw Discord plugin core (plugin-sdk), not the extension. The extension code at extensions/discord/src/channel.ts initializes connected: false (line 347) and reads it via runtime?.connected ?? false (line 405), but connected is never set to true by the core SDK after the discord.js client emits its ready event.

This causes:

The health-monitor to always find the channel "disconnected"
Inbound events to never be processed (likely gated by connected state)
Network ruled out
TCP keepalive: 7200s (default)
Raw WebSocket to Discord: stable 5+ minutes
WhatsApp WebSocket: stable (same container)
Container has outbound internet access, no proxy
Steps to Reproduce
Configure Discord channel with token and guild allowlist
Start gateway
Send @mention in an allowed channel
Observe no response; check logs for health-monitor: restarting (reason: disconnected) at 300s
Additional note
Also seeing Failed to read config: Cannot access 'ANTHROPIC_MODEL_ALIASES' before initialization on every startup in 2026.3.12 (possibly related initialization order bug).

hardy moonBOT
#

Dois pontos bem importantes aqui:

  1. Não é discord.js no OpenClaw — o plugin de Discord usa @buape/carbon. O gateway.isConnected (que alimenta runtime.connected) só vira true depois de receber READY/RESUMED.

  2. O sintoma “WS abre + REST funciona + nunca fica connected + nunca chega MESSAGE_CREATE” costuma ser Discord fechando a sessão por intents privilegiadas (close code 4014), porque o OpenClaw sempre pede MessageContent intent. Se isso não estiver habilitado no Developer Portal, não chega READY e nada inbound vai ser processado.

O que eu preciso pra cravar (e provavelmente resolver em 2 minutos):

  • Confirma no Discord Developer Portal → Bot → Privileged Gateway Intents que Message Content Intent está ON (docs: https://docs.openclaw.ai/channels/discord#enable-privileged-intents)
  • Cola aqui um trecho curto de log (sem token) contendo linhas discord: desde o start atĂ© a primeira desconexĂŁo, especialmente algo como:
    • WebSocket connection closed with code XXXX
    • Fatal Gateway error: XXXX

Se vocĂŞ nĂŁo estiver vendo essas linhas, roda o gateway com mais verbosidade pra capturar isso:

  • openclaw gateway --verbose
    ou seta logging.level pra debug e olha via openclaw logs --follow.
rough jewel
#

Thanks for the insight about Carbon! That helps a lot.

However, I don't think it's 4014 (Disallowed Intents) because:

My manual WebSocket test used intents = 38791 (includes MessageContent 1<<15, GuildMembers 1<<1, Presence 1<<8, GuildMessages 1<<9, etc.) — same privileged intents Carbon would request. Result:

CopyCopied!
HELLO received, interval: 41250
IDENTIFY with intents: 38791
READY! Bot: Aura Nexa #0826, Guilds: 1
GUILD_CREATE: Grupo Nexa
MESSAGE_CREATE: "<@bot_id> teste" from=ggcruz
Full READY + full content MESSAGE_CREATE received. If it were 4014, the gateway would reject the connection before READY.

All 3 privileged intents are enabled in the Developer Portal (confirmed) and in the config:

JSON
Capabilities: messageContent=limited guildMembers=limited presence=limited

No close codes found in the logs. Searched for 4014, 4013, 4012, etc — nothing. Carbon seems to fail silently.

What the logs show:

CopyCopied!
T+0s → "starting provider (@Aura Nexa)"
T+2s → "discord channels resolved" (REST API)
T+2s → "discord channel users resolved"
(no READY log, no error, no close code — silence)
T+300s → "health-monitor: restarting (reason: disconnected)"
My theory: Carbon's gateway WebSocket connects at TCP level but something in the IDENTIFY/initialization is different. The connection closes before READY but Carbon doesn't log the close code.

Could you check: Is there a way to enable debug/verbose logging for the Carbon gateway? Or is there a known issue with @buape/carbon on Node 25.x?

Environment: OpenClaw 2026.3.12, Node 25.8.1, Docker container, Linux 6.8.0-101-generic

hardy moonBOT
#

Você está repostando o mesmo texto, mas ainda falta um detalhe objetivo pra separar “bug no plugin” de “Discord rejeitando a sessão / config bloqueando inbound”.

Top 3 checagens que resolvem 90% disso:

1) Privileged intent (o mais provável)

O OpenClaw sempre solicita Message Content Intent. Se isso estiver OFF no Developer Portal, o Discord geralmente fecha o gateway com 4014 e você nunca recebe READY → runtime.connected fica false e não chega MESSAGE_CREATE pro handler.

Confirma pra mim: Message Content Intent está ON? (sim/não)
Docs: https://docs.openclaw.ai/channels/discord#enable-privileged-intents

2) Teste rápido pra provar se inbound está chegando

VocĂŞ consegue fazer o bot responder em DM?

  • Manda uma DM pro bot (sem guild).
  • Se inbound estiver ok, ele deve responder com cĂłdigo de pairing (ou alguma resposta).

Se DM funciona, mas guild não, então o “não processa inbound” pode ser política/allowlist/requireMention (evento chega, mas o OpenClaw ignora).

#

3) Log com close code (preciso disso)

Cole aqui só as linhas discord: do start até a primeira queda, procurando algo tipo:

  • WebSocket connection closed with code ####
  • Fatal Gateway error: ####

Se nĂŁo estiver aparecendo, rode com mais verbosidade:

  • openclaw gateway --verbose

Com essas 3 respostas (Intent ON/OFF + DM funciona? + close code), dá pra fechar a causa sem chute.

#

Isso agora ficou bem mais “assinável”, e bate com um bug já conhecido no Discord monitor do OpenClaw (não é discord.js).

O que está acontecendo (provável root cause)

No monitorDiscordProvider() o OpenClaw cria o Client (e o GatewayPlugin abre o WebSocket imediatamente no constructor), mas ele sĂł registra os listeners de MESSAGE_CREATE depois de:

  1. await deployDiscordCommands() (deploy de slash commands)
  2. várias resoluções via REST / setup

Se o deploy de comandos estiver lento ou travado (rate limit de upload de comandos do Discord, retries, etc.), o código nunca chega na parte que registra DiscordMessageListener → você vê REST funcionando, mas zero inbound e runtime.connected fica false (porque o lifecycle também só começa depois).

Isso é exatamente a história documentada no issue “Discord bot cannot receive messages” (#4555):

  • workaround: desativar deploy de comandos nativos
  • causa: deploy bloqueando a inicialização “real” do inbound

Workaround imediato (pra destravar inbound)

Desativa slash commands nativos:

#
channels: {
  discord: {
    commands: {
      native: false,
      // opcional: se existir no seu setup e vocĂŞ quer manter /skill global:
      // nativeSkills: false,
    }
  }
}

Reinicia o gateway e testa um @mention de novo.

Se isso resolver, confirma 100% que vocĂŞ estava preso no deployDiscordCommands().

Como confirmar em 10s pelos logs

#

Procura se nunca aparece algo como:

  • logged in to discord as ...

Se não aparece, você está travando antes disso (muito provavelmente no deploy).

Sobre o erro ANTHROPIC_MODEL_ALIASES before initialization

Isso parece um segundo bug de init order em 2026.3.12 (se for consistente). Eu separaria em outro report, porque pode estar mascarando logs/fluxo também.

Se puder: posta um trecho curto do log entre starting provider e os 300s (sem token). Se vocĂŞ topar, o prĂłximo passo certo Ă© abrir issue no GitHub referenciando #4555 + dizendo que ainda reproduz em 2026.3.12.

#

Seu log “starting provider → channels resolved → silêncio total até o health-monitor em 300s” é praticamente a assinatura de que o monitor nunca chegou na parte que:

  • registra os listeners de inbound (DiscordMessageListener)
  • inicia o lifecycle (runDiscordGatewayLifecycle), que Ă© quem tambĂ©m atualiza runtime.connected

E aí você realmente não vai ver READY / close codes / “discord gateway: …”, porque o logger do gateway só é anexado dentro do lifecycle.

Por que isso acontece (bem comum)

O OpenClaw faz await deployDiscordCommands() logo no começo. Se o deploy de slash commands ficar lento ou preso em retry (rate limit de uploads de comandos, muita lista de comandos por skills, etc.), a inicialização “real” do inbound fica bloqueada e parece que “Carbon falha silenciosamente”.

Isso já foi investigado no tracker “Discord bot cannot receive messages” (#4555). Workaround que destrava muita gente:

Workaround pra confirmar (e provavelmente resolver)

Desabilita deploy de comandos nativos do Discord:

#
channels: {
  discord: {
    commands: { native: false }
  }
}

Reinicia o gateway e testa de novo um @mention.

Se apĂłs isso vocĂŞ passar a ver:

  • logged in to discord as ...
  • discord gateway: WebSocket connection opened/closed ... (com --verbose)
  • runtime.connected mudando

…então o culpado era mesmo o deploy bloqueando o resto.

#

“Como habilitar debug/verbose do Carbon gateway?”

O que existe hoje no OpenClaw é log via discord gateway: ... (mensagens de “WebSocket connection opened/closed…”) — ele aparece quando você roda:

  • openclaw gateway --verbose (console)
  • e/ou logging.level: "debug" / "trace" (pra cair em file logs)

Mas de novo: vocĂŞ sĂł vai ver isso se o cĂłdigo chegar no lifecycle (ou seja, depois de sair do deploy).

Node 25.x

Tem vários relatos desse “Discord inbound some” em Node 25.x, mas o padrão mais consistente não é “bug do Node”: é deploy/ordem de init + rate limit/retry.

Se vocĂŞ testar commands.native: false e continuar mudo do mesmo jeito, aĂ­ sim eu iria pro plano B:

  1. testar com Node 24 LTS (só pra eliminar variável)
  2. abrir issue no GitHub com esse timeline + config + openclaw gateway --verbose (linkando #4555)

Se você topar: depois de setar commands.native: false, me diz se apareceu logged in to discord as ... e se o bot começou a responder. Isso já decide o diagnóstico.