chenhg5/cc-connect · error

discord: send: %w

Error message

discord: send: %w

What it means

sendChannelReply failed on the discordgo message-send call. It either uses ChannelMessageSendReply (with a MessageReference to reply inline) or falls back to ChannelMessageSend when replying in a thread or when no message ID is available. Any Discord API rejection of the send — most commonly 403 Missing Permissions, 404 Unknown Channel/Message, or a network failure — is wrapped here.

Source

Thrown at platform/discord/discord.go:1019

				return fmt.Errorf("discord: send fallback: %w", err)
			}
		}
	}
	return nil
}

func (p *Platform) sendChannelReply(rc replyContext, content string) error {
	chunks := core.SplitMessageCodeFenceAware(wrapTablesInCodeBlocks(content), maxDiscordLen)
	for _, chunk := range chunks {
		var err error
		if rc.useThreadChannel() || rc.messageID == "" {
			_, err = p.session.ChannelMessageSend(rc.targetChannelID(), chunk)
		} else {
			ref := &discordgo.MessageReference{MessageID: rc.messageID}
			_, err = p.session.ChannelMessageSendReply(rc.channelID, chunk, ref)
		}
		if err != nil {
			return fmt.Errorf("discord: send: %w", err)
		}
	}
	return nil
}

func (p *Platform) sendChannel(rc replyContext, content string) error {
	chunks := core.SplitMessageCodeFenceAware(wrapTablesInCodeBlocks(content), maxDiscordLen)
	for _, chunk := range chunks {
		_, err := p.session.ChannelMessageSend(rc.targetChannelID(), chunk)
		if err != nil {
			return fmt.Errorf("discord: send: %w", err)
		}
	}
	return nil
}

// SendImage sends an image to the channel or interaction.
// Implements core.ImageSender.

View on GitHub (pinned to 4000b2338a)

Solutions

  1. Read the wrapped discordgo error code: 403 → add Send Messages/View Channel/Read Message History perms for the bot role; 404 → the channel or referenced message no longer exists
  2. Grant the bot the required permissions or move the bot to a role with channel access
  3. If the referenced message may vanish, clear messageID so sendChannelReply uses the plain ChannelMessageSend path
  4. Check for 429 rate-limit errors and add backoff/retry around replies

Example fix

// before
_, err = p.session.ChannelMessageSendReply(rc.channelID, chunk, ref)
// after
_, err = p.session.ChannelMessageSendReply(rc.channelID, chunk, ref)
if isUnknownMessage(err) {
    _, err = p.session.ChannelMessageSend(rc.targetChannelID(), chunk)
}
Defensive patterns

Strategy: retry

Validate before calling

perms, _ := p.session.State.UserChannelPermissions(p.botID, rc.channelID)
if perms&discordgo.PermissionSendMessages == 0 {
    return fmt.Errorf("bot cannot send in channel %s", rc.channelID)
}

Try / catch

var apiErr *discordgo.RESTError
if errors.As(err, &apiErr) && apiErr.Message.Code == 10008 {
    // Unknown Message: referenced message was deleted — resend without reference
    _, err = p.session.ChannelMessageSend(rc.targetChannelID(), chunk)
}

Prevention

When it happens

Trigger: Reply() on a normal channel message where the bot lacks Send Messages permission; the referenced messageID was deleted (404 Unknown Message on the reply endpoint); the channel is read-only or the bot was kicked from the guild; transient network/proxy failure to discord.com.

Common situations: Bot missing role permissions in a restricted channel; user deleted their message before the agent reply arrived; message content intent/permission changes after a server reshuffle; Discord rate limits (429) under heavy reply traffic.

Understand the failure class

Background: "API error: {status}" and "HTTP 401/403/404/429/5xx" errors: non-2xx HTTP responses explained — this error's family across 27 libraries.

Related errors


AI-assisted analysis of chenhg5/cc-connect@4000b2338a (2026-09-06). Data as JSON: /api/errors/305e55d54c667093. Report an issue: GitHub.