chenhg5/cc-connect · error

empty media_id in upload response: %s

Error message

empty media_id in upload response: %s

What it means

The media upload API answered HTTP 200 with errcode 0 (success), yet the media_id field in the JSON response is empty. Since a valid media_id is required to send the media later, the platform treats this as a failed upload and returns the raw response body for inspection. This guards against silently succeeding with an unusable media id.

Source

Thrown at platform/dingtalk/dingtalk.go:1402

	slog.Debug("dingtalk: media upload response", "status", resp.StatusCode, "body", string(respBody))

	var uploadResp struct {
		ErrCode int    `json:"errcode"`
		ErrMsg  string `json:"errmsg"`
		MediaID string `json:"media_id"`
		Type    string `json:"type"`
	}
	if err := json.Unmarshal(respBody, &uploadResp); err != nil {
		return "", fmt.Errorf("decode upload response: %w, body: %s", err, respBody)
	}

	if uploadResp.ErrCode != 0 {
		return "", fmt.Errorf("upload API error %d: %s", uploadResp.ErrCode, uploadResp.ErrMsg)
	}

	if uploadResp.MediaID == "" {
		return "", fmt.Errorf("empty media_id in upload response: %s", respBody)
	}

	slog.Debug("dingtalk: media uploaded successfully", "media_id", uploadResp.MediaID, "type", mediaType, "size", len(data))
	return uploadResp.MediaID, nil
}

func (p *Platform) Stop() error {
	if p.streamCtxCancel != nil {
		p.streamCtxCancel()
	}
	if p.streamClient != nil {
		p.streamClient.Close()
	}
	return nil
}

// formatReplyContent prepends quoted text to the message content when the user
// replies to / quotes a previous message. richText is parsed from the raw JSON

View on GitHub (pinned to 4000b2338a)

Solutions

  1. Inspect the body in the error message — check what keys the response actually contains (media_id vs mediaId, nested payload, etc.).
  2. Confirm you are calling the current official media/upload endpoint for your app type (enterprise internal app vs. custom robot).
  3. Check the DingTalk Open Platform changelog for response schema changes for media upload.
  4. Retest with a small, well-formed image upload to rule out type-specific quirks.
  5. If using a mock/proxy for testing, ensure it returns a non-empty media_id field.

Example fix

// caller-side guard
mediaID, err := platform.UploadMedia(ctx, data, "image")
if err != nil {
    if strings.Contains(err.Error(), "empty media_id") {
        slog.Warn("dingtalk upload returned success but no media_id; check API version/response keys")
    }
    return err
}
Defensive patterns

Strategy: validation

Validate before calling

// caller-side sanity check after a successful upload
mediaID, err := uploadMedia(ctx, data, mediaType)
if err == nil && mediaID == "" {
    return fmt.Errorf("upload returned empty media_id")
}

Try / catch

mediaID, err := uploadMedia(ctx, data, mediaType)
if err != nil {
    if strings.Contains(err.Error(), "empty media_id") {
        // treat as failure; log raw response for API-version debugging
        slog.Error("dingtalk upload succeeded without media_id; check API version", "detail", err.Error())
    }
    return err
}

Prevention

When it happens

Trigger: DingTalk returns a success envelope whose media_id key is absent, null, or an empty string — e.g. a changed/renamed response field in some API version, a success response for a type the account cannot actually store, or a partially-finished upload acknowledged early.

Common situations: DingTalk API behavior change or regional endpoint difference; responses proxied/rewritten by middleware stripping fields; uploading with an app type that acknowledges but does not persist the media; testing against a mocked/stubbed DingTalk API.

Related errors


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