chenhg5/cc-connect · error

qqbot: upload rich media: empty file_info

Error message

qqbot: upload rich media: empty file_info

What it means

After a successful apiRequestJSON call, uploadRichMedia validates that the QQ rich-media API actually returned a non-empty file_info token, which is required to attach the media to a message. An empty file_info means the API responded 2xx but without the expected payload — the upload did not really complete, so the adapter treats it as an error.

Source

Thrown at platform/qqbot/qqbot.go:298

	b64 := base64.StdEncoding.EncodeToString(data)
	reqBody := map[string]any{
		"file_type":    fileType,
		"file_data":    b64,
		"srv_send_msg": false,
	}
	if fileType == 4 && fileName != "" {
		reqBody["file_name"] = fileName
	}

	var result struct {
		FileInfo string `json:"file_info"`
	}
	if err := p.apiRequestJSON("POST", url, reqBody, &result); err != nil {
		return "", err
	}
	if result.FileInfo == "" {
		return "", fmt.Errorf("qqbot: upload rich media: empty file_info")
	}
	return result.FileInfo, nil
}

// apiRequestJSON is like apiRequest but also decodes the response body into result.
func (p *Platform) apiRequestJSON(method, url string, body any, result any) error {
	var bodyReader io.Reader
	if body != nil {
		data, err := json.Marshal(body)
		if err != nil {
			return fmt.Errorf("qqbot: marshal body: %w", err)
		}
		bodyReader = bytes.NewReader(data)
	}

	token, err := p.getAccessToken()
	if err != nil {
		return fmt.Errorf("qqbot: get token: %w", err)

View on GitHub (pinned to 4000b2338a)

Solutions

  1. Retry the upload — the condition is often transient on QQ's media service.
  2. Log the full raw response body (add temporary logging in apiRequestJSON) to see what was actually returned.
  3. Verify the file_type (1=image, 4=file) and payload size match QQ Bot rich-media API requirements.
  4. Check for a QQ Open Platform changelog entry about the rich-media response format.
  5. Confirm the bot's permissions for the target group/c2c media upload.

Example fix

// before
fileInfo, err := p.uploadRichMedia(rctx, 1, img.Data, "")
if err != nil { return err }
// after
var fileInfo string
for i := 0; i < 2; i++ {
    fileInfo, err = p.uploadRichMedia(rctx, 1, img.Data, "")
    if err == nil { break }
    if !strings.Contains(err.Error(), "empty file_info") { break }
    time.Sleep(time.Second)
}
if err != nil { return err }
Defensive patterns

Strategy: retry

Validate before calling

// Validate payload before upload so the API cannot fail softly
if len(data) == 0 { return errors.New("qqbot: empty upload payload") }

Try / catch

fileInfo, err := p.uploadRichMedia(rctx, fileType, data, name)
if err != nil {
    if strings.Contains(err.Error(), "empty file_info") {
        // transient/soft API failure: retry once, then log raw body
    }
}

Prevention

When it happens

Trigger: The rich-media endpoint returns HTTP 200 with a body lacking file_info (e.g. an error object in disguise, an async-processing response, or an API behavior change).

Common situations: QQ API version drift changing the response shape; uploading a file type the bot lacks permission for, with the API failing softly; intermittent media-service degradation returning empty bodies.

Understand the failure class

Background: "empty response", "returned no data", "empty embeddings": what HTTP 200-with-empty-body errors mean across libraries — this error's family across 36 libraries.

Related errors


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