chenhg5/cc-connect · error

qqbot: upload file: %w

Error message

qqbot: upload file: %w

What it means

This error wraps any failure from the QQ Bot rich-media upload that happens inside SendFile (platform/qqbot/qqbot.go:396). Before a file can be sent as a media message (msg_type 7), it must be uploaded to QQ's rich media API to obtain a file_info handle; if that upload fails (network error, HTTP error, auth failure), the error is wrapped with 'qqbot: upload file'. It is a transport/API-level failure, not a problem with the reply context itself.

Source

Thrown at platform/qqbot/qqbot.go:396

}

var _ core.ImageSender = (*Platform)(nil)

// buttonDataPrefix is the prefix for QQ Bot keyboard button_data values.
// Format: perm:<decision>:<session_key>
const buttonDataPrefix = "perm:"

// SendFile uploads and sends a file via QQ Bot rich media API.
// Implements core.FileSender.
func (p *Platform) SendFile(ctx context.Context, replyCtx any, file core.FileAttachment) error {
	rctx, ok := replyCtx.(*replyContext)
	if !ok {
		return fmt.Errorf("qqbot: SendFile: invalid reply context type %T", replyCtx)
	}

	fileInfo, err := p.uploadRichMedia(rctx, 4, file.Data, file.FileName)
	if err != nil {
		return fmt.Errorf("qqbot: upload file: %w", err)
	}

	var url string
	switch rctx.messageType {
	case "group":
		url = fmt.Sprintf("%s/v2/groups/%s/messages", p.apiBase(), rctx.groupOpenID)
	case "c2c":
		url = fmt.Sprintf("%s/v2/users/%s/messages", p.apiBase(), rctx.userOpenID)
	default:
		return fmt.Errorf("qqbot: unknown message type %q", rctx.messageType)
	}

	body := map[string]any{
		"msg_type": 7,
		"media":    map[string]any{"file_info": fileInfo},
	}
	if rctx.eventMsgID != "" {
		body["msg_id"] = rctx.eventMsgID

View on GitHub (pinned to 4000b2338a)

Solutions

  1. Check the wrapped cause (%w) in the error chain to see if it was auth, HTTP status, or network.
  2. Verify appId/appSecret in config.toml are valid QQ Bot credentials by restarting and watching for token refresh errors.
  3. Retry with a smaller file; confirm the file type/size is within QQ Bot rich media limits.
  4. Test outbound connectivity to the QQ Bot API host and check for proxy/firewall interference.

Example fix

// before
err := platform.SendFile(ctx, replyCtx, core.FileAttachment{Data: hugeBlob, FileName: "video.mp4"})
// after
if len(hugeBlob) > maxQQFileSize {
    return fmt.Errorf("file too large for qqbot: %d bytes", len(hugeBlob))
}
if err := platform.SendFile(ctx, replyCtx, core.FileAttachment{Data: hugeBlob, FileName: "video.mp4"}); err != nil {
    slog.Error("send file failed", "err", err) // inspect wrapped 'qqbot: upload file' cause
}
Defensive patterns

Strategy: try-catch

Validate before calling

if len(file.Data) == 0 || file.FileName == "" {
    return fmt.Errorf("refusing to send empty file %q", file.FileName)
}

Try / catch

if err := platform.SendFile(ctx, replyCtx, file); err != nil {
    var transient = strings.Contains(err.Error(), "returned 5") || strings.Contains(err.Error(), "token request failed")
    if transient { /* retry with backoff */ }
    slog.Error("qqbot send file failed", "err", err)
}

Prevention

When it happens

Trigger: Calling SendFile on a qqbot Platform when uploadRichMedia (media type 4 = file) returns an error: token refresh failure, HTTP >=300 from the rich media endpoint, network timeout, or a decode failure of the upload response.

Common situations: Expired/invalid appId or appSecret causing auth failure during upload; oversized or unsupported file; QQ Bot API outage or rate limiting; no network access from the host.

Understand the failure class

Background: "API request failed": what wrapped HTTP errors from external APIs mean and how to find the real cause — this error's family across 29 libraries.

Related errors


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