chenhg5/cc-connect · error
api returned status %d
Error message
api returned status %d
What it means
getDownloadURL calls DingTalk's media download API to obtain a temporary download URL for an incoming image/file/audio message. When the API responds with any HTTP status other than 200, the function aborts and wraps the status code in this error. It indicates the download-ticket request itself failed before a URL could be parsed.
Source
Thrown at platform/dingtalk/dingtalk.go:708
defer cancel()
req, err := http.NewRequestWithContext(ctx, http.MethodPost,
"https://api.dingtalk.com/v1.0/robot/messageFiles/download",
bytes.NewReader(bodyBytes))
if err != nil {
return "", fmt.Errorf("create request: %w", err)
}
req.Header.Set("Content-Type", "application/json")
req.Header.Set("x-acs-dingtalk-access-token", token)
resp, err := p.httpClient.Do(req)
if err != nil {
return "", fmt.Errorf("do request: %w", err)
}
defer func() { _ = resp.Body.Close() }()
if resp.StatusCode != http.StatusOK {
return "", fmt.Errorf("api returned status %d", resp.StatusCode)
}
var result downloadResponse
if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
return "", fmt.Errorf("decode response: %w", err)
}
if result.DownloadUrl == "" {
return "", fmt.Errorf("empty downloadUrl in response")
}
return result.DownloadUrl, nil
}
func (p *Platform) getAccessToken() (string, error) {
p.tokenMu.Lock()
defer p.tokenMu.Unlock()
View on GitHub (pinned to 4000b2338a)
Solutions
- Check the status code in the error message: 401/403 means the access token is invalid — verify appKey/appSecret in config.toml and restart.
- If the code is 4xx referencing the downloadCode, the media code likely expired; ask the user to resend the image/file.
- For 5xx, retry getDownloadURL with backoff after confirming the DingTalk status page shows no outage.
- Confirm the robot/app has media download permissions in the DingTalk developer console.
- Enable debug logging to capture the full request/response and compare against DingTalk API docs.
Example fix
// before: single attempt, no retry on transient status
url, err := p.getDownloadURL(ctx, code)
if err != nil { return fmt.Errorf("dingtalk: get download url: %w", err) }
// after: retry transient statuses
url, err := p.getDownloadURL(ctx, code)
if err != nil {
if strings.Contains(err.Error(), "status 5") {
time.Sleep(2 * time.Second)
url, err = p.getDownloadURL(ctx, code)
}
if err != nil { return fmt.Errorf("dingtalk: get download url: %w", err) }
} Defensive patterns
Strategy: retry
Validate before calling
if !strings.HasPrefix(mediaCode, "") && time.Since(mediaCodeReceivedAt) < 5*time.Minute {
// code likely still valid, safe to call
} Try / catch
url, err := p.getDownloadURL(ctx, code)
if err != nil {
var status int
if _, serr := fmt.Sscanf(err.Error(), "api returned status %d", &status); serr == nil && status >= 500 {
time.Sleep(2 * time.Second)
url, err = p.getDownloadURL(ctx, code)
}
if err != nil { return fmt.Errorf("download url: %w", err) }
} Prevention
- Process media messages immediately; DingTalk downloadCodes expire quickly.
- Keep appKey/appSecret current and monitor DingTalk status for outages.
- Log status codes to distinguish config (4xx) vs outage (5xx) issues.
- Refresh the access token before its expiry window (code already caches with 5-minute buffer).
When it happens
Trigger: Called from handleImageMessage, handleFileMessage, or downloadAudio when the POST to the DingTalk media/download endpoint returns a non-200 status, e.g. 400 for a malformed downloadCode, 401/403 for an expired or invalid access token, 404 for an expired code, or 5xx from DingTalk.
Common situations: Expired downloadCode (DingTalk media codes are short-lived and single-use), an access token that expired or was revoked after an app-secret rotation, wrong appKey/appSecret config, or transient DingTalk server errors (500/502/503).
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
- do request: %w
- http %d: %s
- do request: %w
- create AI card: status=%d, body=%s
- stream AI card: status=%d, body=%s
AI-assisted analysis of chenhg5/cc-connect@4000b2338a (2026-09-06).
Data as JSON: /api/errors/1ea846923e99946f.
Report an issue: GitHub.