chenhg5/cc-connect · error
first-chunk: unexpected status %d
Error message
first-chunk: unexpected status %d
What it means
Thrown when the first-chunk probe receives any HTTP status other than 200 or 206 — e.g. 401/403 (auth rejected), 404 (message or file_key gone), or 5xx. The chunked downloader only understands those two success shapes and refuses to interpret anything else, giving the raw status code for diagnosis. The caller then falls back to resourceSingleGet, which reports a fuller status+body error if it also fails.
Source
Thrown at platform/feishu/resource_download.go:181
return nil, 0, fmt.Errorf("read first-chunk body: %w", err)
}
return body, total, nil
case http.StatusOK:
// Server ignored Range and sent the full body. We deliberately
// honour it and skip the chunked loop — this matches pre-#1741
// behaviour for files small enough that Feishu doesn't truncate.
body, err := io.ReadAll(io.LimitReader(resp.Body, p.resourceMaxBytes+1))
if err != nil {
return nil, 0, fmt.Errorf("read full body: %w", err)
}
if int64(len(body)) > p.resourceMaxBytes {
return nil, 0, fmt.Errorf("resource too large: body exceeds cap %d", p.resourceMaxBytes)
}
return body, 0, nil
default:
return nil, 0, fmt.Errorf("first-chunk: unexpected status %d", resp.StatusCode)
}
}
// resourceFetchRemainingChunks loops Range GETs starting after the first
// byte, concatenates them with `first`, and verifies the total size matches
// what the probe advertised.
func (p *Platform) resourceFetchRemainingChunks(ctx context.Context, token, messageID, fileKey, resType string, total int64, first []byte) ([]byte, error) {
buf := bytes.NewBuffer(make([]byte, 0, total))
buf.Write(first)
chunkSize := p.resourceChunkSize
if chunkSize > resourceRangeMaxRangeHeaderBytes {
chunkSize = resourceRangeMaxRangeHeaderBytes
}
chunks := 1 // count the first byte we already have
for offset := int64(1); offset < total; offset += chunkSize {
end := offset + chunkSize - 1
if end >= total {View on GitHub (pinned to 4000b2338a)
Solutions
- Read the fallback resourceSingleGet error, which includes a body snippet with Feishu's code/msg
- On 401/403: re-check app permissions (im:resource) and tenant token minting; the next download remints the token
- On 404: the message or file_key no longer exists — treat as unrecoverable and inform the user
- On 5xx: retry later; check Feishu status/uptime
Example fix
null
Defensive patterns
Strategy: fallback
Validate before calling
null
Type guard
null
Try / catch
if err != nil && strings.Contains(err.Error(), "unexpected status") {
var apiErr *feishu.APIError
if errors.As(err, &apiErr) && apiErr.Code == 99991672 { /* 404: file gone */ }
} Prevention
- Download resources promptly after message receipt — files can be deleted later (404)
- Keep app token minting healthy so downloads don't race token expiry (401)
- Maintain im:resource scope grants; re-verify after app permission changes (403)
- Retry 5xx-class failures with backoff; treat 4xx as terminal and user-facing
When it happens
Trigger: resourceDownloadHTTP returns 3xx/4xx/5xx on the Range bytes=0-0 GET: expired tenant token mid-flight, wrong messageID/fileKey, resource already deleted, or Feishu server error.
Common situations: Bot's app removed from the chat (403), user deletes the message/file before the bot downloads it (404), token cache expiry race (401), Feishu incident (5xx).
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
- usage endpoint returned status %d: %s
- minimax tts API %d: %s
- build first-chunk request: %w
- first-chunk request: %w
- first-chunk: 206 without parseable Content-Range %q
AI-assisted analysis of chenhg5/cc-connect@4000b2338a (2026-09-06).
Data as JSON: /api/errors/d77cdd39b5d68f00.
Report an issue: GitHub.