chenhg5/cc-connect · error

discord: SendImage: invalid reply context type %T

Error message

discord: SendImage: invalid reply context type %T

What it means

SendImage was called with a reply-context value that is neither *interactionReplyCtx nor replyContext — the only two context types the Discord platform produces. The %T verb prints the offending Go type. This is a programming/contract error in the caller, not a Discord API failure: the message never reached Discord.

Source

Thrown at platform/discord/discord.go:1090

			slog.Warn("discord: interaction image failed, falling back to channel message", "error", err)
			_, err = p.session.ChannelMessageSendComplex(rc.channelID, &discordgo.MessageSend{
				Files: []*discordgo.File{newFile()},
			})
			if err != nil {
				return fmt.Errorf("discord: send image fallback: %w", err)
			}
		}
		return nil
	case replyContext:
		_, err := p.session.ChannelMessageSendComplex(rc.targetChannelID(), &discordgo.MessageSend{
			Files: []*discordgo.File{newFile()},
		})
		if err != nil {
			return fmt.Errorf("discord: send image: %w", err)
		}
		return nil
	default:
		return fmt.Errorf("discord: SendImage: invalid reply context type %T", rctx)
	}
}

func (p *Platform) SendFile(ctx context.Context, rctx any, file core.FileAttachment) error {
	name := file.FileName
	if name == "" {
		name = "attachment"
	}

	newFile := func() *discordgo.File {
		return &discordgo.File{
			Name:        name,
			ContentType: file.MimeType,
			Reader:      bytes.NewReader(file.Data),
		}
	}

	switch rc := rctx.(type) {

View on GitHub (pinned to 4000b2338a)

Solutions

  1. Only pass the ReplyCtx captured from an incoming Discord message into SendImage
  2. Add a nil/type check at the call site and skip or reroute the send if the context is foreign
  3. If bridging platforms, create a Discord-native context for the target channel instead of reusing the foreign one
  4. Enable logging of the %T value to find which code path produced the wrong context

Example fix

// before
err := platform.SendImage(ctx, msg.ReplyCtx, img) // ReplyCtx may be foreign
// after
if _, ok := msg.ReplyCtx.(discord.ReplyContext); !ok {
    return fmt.Errorf("cannot send image: not a discord reply context")
}
err := platform.SendImage(ctx, msg.ReplyCtx, img)
Defensive patterns

Strategy: type-guard

Validate before calling

if rctx == nil {
    return fmt.Errorf("cannot send image: missing discord reply context")
}

Type guard

func isDiscordImageCtx(rctx any) bool {
    switch rctx.(type) {
    case *interactionReplyCtx, replyContext:
        return true
    default:
        return false
    }
}

Try / catch

if err := p.SendImage(ctx, rctx, img); err != nil {
    if strings.Contains(err.Error(), "invalid reply context type") {
        slog.Warn("skipping image send: foreign context", "type", fmt.Sprintf("%T", rctx))
        return nil
    }
    return err
}

Prevention

When it happens

Trigger: Passing nil, a stub, or a reply context minted by another platform (Feishu/Telegram/Slack adapters) into discord.Platform.SendImage; custom engine code fabricating its own context struct.

Common situations: Cross-platform message forwarding that carries ReplyCtx values across platform boundaries; engine bugs that drop or replace the context; tests that pass placeholder values.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


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