chenhg5/cc-connect · error
resource API status=%d body=%q
Error message
resource API status=%d body=%q
What it means
The Feishu resource API responded with a non-2xx HTTP status code during a single-GET download. The library reads up to 4 KiB of the response body and includes it in the error so the API's error message (e.g. invalid token, file not found, permission denied) is visible to the developer.
Source
Thrown at platform/feishu/resource_download.go:269
// for small files and as a fallback when the size probe fails. We honour
// resourceMaxBytes via Content-Length + body cap so a misbehaving server
// can't blow up memory.
func (p *Platform) resourceSingleGet(ctx context.Context, token, messageID, fileKey, resType string) ([]byte, error) {
req, err := http.NewRequestWithContext(ctx, http.MethodGet, p.resourceURL(messageID, fileKey, resType), nil)
if err != nil {
return nil, fmt.Errorf("build request: %w", err)
}
req.Header.Set("Authorization", "Bearer "+token)
resp, err := p.resourceDownloadHTTP.Do(req)
if err != nil {
return nil, fmt.Errorf("resource request: %w", err)
}
defer func() { _ = resp.Body.Close() }()
if resp.StatusCode < 200 || resp.StatusCode >= 300 {
body, _ := io.ReadAll(io.LimitReader(resp.Body, 4*1024))
return nil, fmt.Errorf("resource API status=%d body=%q", resp.StatusCode, strings.TrimSpace(string(body)))
}
if cl := resp.ContentLength; cl > p.resourceMaxBytes {
return nil, fmt.Errorf("resource too large: Content-Length=%d exceeds cap %d", cl, p.resourceMaxBytes)
}
// LimitReader caps the body too in case the server lies about
// Content-Length; we read up to cap+1 bytes to detect the lie.
data, err := io.ReadAll(io.LimitReader(resp.Body, p.resourceMaxBytes+1))
if err != nil {
return nil, fmt.Errorf("read resource: %w", err)
}
if int64(len(data)) > p.resourceMaxBytes {
return nil, fmt.Errorf("resource too large: body exceeds cap %d", p.resourceMaxBytes)
}
slog.Debug(p.tag()+": resource downloaded (single GET)",
"file_key", fileKey, "type", resType, "size", len(data))
return data, nilView on GitHub (pinned to 4000b2338a)
Solutions
- Read the body quoted in the error — Feishu's code/msg fields identify the exact cause (invalid token, not found, permission)
- Refresh the tenant_access_token and ensure the app has im:resource / im:message:readonly scopes
- Verify message_id and file_key belong to the same message and that the bot is a member of the chat
- For 5xx/429, retry with backoff; for 401, re-authenticate; for 404, ask the sender to re-share the file
- Check that the token type matches the API (tenant_access_token vs user_access_token)
Defensive patterns
Strategy: try-catch
Validate before calling
// keep token fresh and scopes granted before downloading
token, err := p.ensureFreshTenantToken(ctx)
if err != nil { return nil, fmt.Errorf("auth for resource download: %w", err) } Try / catch
data, err := p.resourceSingleGet(ctx, token, msgID, fileKey, resType)
if err != nil {
if strings.Contains(err.Error(), "resource API status=") {
// parse status + Feishu code from the quoted body:
// 401/99991663 -> refresh token; 404 -> re-request file; 5xx -> backoff retry
return classifyFeishuAPIError(err)
}
return err
} Prevention
- Refresh tenant_access_token proactively before expiry
- Grant the app im:resource / im:message:readonly scopes in the Feishu developer console
- Keep the bot in the chat whose message resources you download
- Apply backoff on 429/5xx instead of immediate retries
When it happens
Trigger: resourceSingleGet receives a status outside 200-299 from the resource endpoint — expired/invalid tenant_access_token (401/99991663-style errors), wrong message_id or file_key (404), missing im:resource permission, or Feishu server error (5xx).
Common situations: Token expired or fetched for the wrong tenant/app; file_key copied from a message in another chat or an expired resource; app lacks the im:message/im:resource scopes; Feishu incident causing 5xx; rate limiting returning 429.
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
- first-chunk: unexpected status %d
- too many redirects
- usage endpoint returned status %d: %s
- reasonix: POST %s returned %d: %s
- init failed: %w
AI-assisted analysis of chenhg5/cc-connect@4000b2338a (2026-09-06).
Data as JSON: /api/errors/424dcbc116cfbc29.
Report an issue: GitHub.