chenhg5/cc-connect · error

resource chunk offset=%d: %w

Error message

resource chunk offset=%d: %w

What it means

This error wraps a failure that occurred while downloading one non-first chunk of a Feishu message resource (file/image) via an HTTP Range request in resourceFetchRemainingChunks. The library chunks large downloads after a size probe and fetches each chunk with resourceRangeChunk; when any chunk fetch fails, it wraps the underlying error with the chunk's byte offset so callers can tell where the assembly broke. The offset is the start byte of the chunk that failed.

Source

Thrown at platform/feishu/resource_download.go:204

// 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 {
			end = total - 1
		}
		n, err := p.resourceRangeChunk(ctx, token, messageID, fileKey, resType, offset, end, total)
		if err != nil {
			return nil, fmt.Errorf("resource chunk offset=%d: %w", offset, err)
		}
		buf.Write(n)
		chunks++
		if err := ctx.Err(); err != nil {
			return nil, err
		}
	}

	if int64(buf.Len()) != total {
		return nil, fmt.Errorf("resource size mismatch: assembled=%d expected=%d", buf.Len(), total)
	}
	slog.Info(p.tag()+": resource chunked download complete",
		"file_key", fileKey, "type", resType, "total", total, "chunks", chunks,
		"chunk_size", chunkSize)
	return buf.Bytes(), nil
}

// parseContentRangeTotal extracts the "total" field from a Content-Range

View on GitHub (pinned to 4000b2338a)

Solutions

  1. Retry the download; resourceRangeChunk already retries transient errors up to maxTransientRetries, so persistent failures usually mean network or auth issues — refresh the tenant_access_token and retry
  2. Check that the token passed to resourceDownloadStream is a valid, unexpired tenant_access_token with im:resource read permission
  3. Verify network/proxy allows HTTP Range (partial content) requests to open.feishu.cn
  4. Inspect the wrapped cause (%w) in logs — the underlying resourceRangeChunk error (status code, network error) names the real problem
  5. If the file is small enough, rely on resourceSingleGet (used when the size probe fails) which avoids chunking entirely

Example fix

// before: single call, no token refresh on long downloads
data, err := p.resourceDownloadStream(ctx, staleToken, msgID, fileKey, resType)
// after: obtain a fresh token before starting a chunked download
token, err := p.freshTenantToken(ctx)
if err != nil { return nil, err }
data, err := p.resourceDownloadStream(ctx, token, msgID, fileKey, resType)
Defensive patterns

Strategy: retry

Validate before calling

// before download
if token == "" { return fmt.Errorf("missing tenant_access_token") }
if msgID == "" || fileKey == "" { return fmt.Errorf("empty message_id/file_key") }

Try / catch

data, err := p.resourceDownloadStream(ctx, token, msgID, fileKey, resType)
if err != nil {
    if strings.Contains(err.Error(), "resource chunk offset=") {
        // refresh token, wait briefly, retry once
        return retryDownload(ctx, msgID, fileKey, resType)
    }
    return err
}

Prevention

When it happens

Trigger: Calling resourceDownloadStream for a resource whose probed total size exceeds the chunk size, causing resourceFetchRemainingChunks to issue Range GETs; a chunk's HTTP request fails (network error, non-206 status, server rejecting Range, auth token expiring mid-download), so resourceRangeChunk returns an error.

Common situations: Flaky network or proxy dropping long multi-chunk downloads; Feishu API returning 4xx/5xx on Range requests because the tenant_access_token expired between chunks; server ignoring the Range header and returning 200 instead of 206; corporate firewall blocking partial-content requests.

Understand the failure class

Background: 'Something went wrong' / 'Request failed (500)' / 'HTTP error! status: 404' — what failed HTTP requests actually mean and how to find the real cause — this error's family across 28 libraries.

Related errors


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