github/github-mcp-server · error
failed to download log content for job %d: %w
Error message
failed to download log content for job %d: %w
What it means
Returned by getJobLogData (pkg/github/actions.go:153) when downloadLogContent fails after the log URL was already obtained. It wraps one of three inner failures: transport error fetching the signed blob URL ('failed to download logs: %w'), a non-200 status ('failed to download logs: HTTP %d'), or a body-streaming error ('failed to process log content: %w'). The httpResp is converted to a github.Response so error-reporting middleware still sees status context.
Source
Thrown at pkg/github/actions.go:153
}
defer func() { _ = resp.Body.Close() }()
result := map[string]any{
"job_id": jobID,
}
if jobName != "" {
result["job_name"] = jobName
}
if returnContent {
// Download and return the actual log content
content, originalLength, httpResp, err := downloadLogContent(ctx, url.String(), tailLines, contentWindowSize) //nolint:bodyclose // Response body is closed in downloadLogContent, but we need to return httpResp
if err != nil {
var ghResp *github.Response
if httpResp != nil {
ghResp = &github.Response{Response: httpResp}
}
return nil, ghResp, fmt.Errorf("failed to download log content for job %d: %w", jobID, err)
}
result["logs_content"] = content
result["message"] = "Job logs content retrieved successfully"
result["original_length"] = originalLength
} else {
// Return just the URL
result["logs_url"] = url.String()
result["message"] = "Job logs are available for download"
result["note"] = "The logs_url provides a download link for the individual job logs in plain text format. Use return_content=true to get the actual log content."
}
return result, resp, nil
}
func downloadLogContent(ctx context.Context, logURL string, tailLines int, maxLines int) (string, int, *http.Response, error) {
prof := profiler.New(nil, profiler.IsProfilingEnabled())
finish := prof.Start(ctx, "log_buffer_processing")
View on GitHub (pinned to 0ea1f775a7)
Solutions
- Unwrap the inner error to identify which of the three failures occurred, then apply its specific fix
- Retry immediately - a fresh call re-obtains a fresh signed URL, fixing expiry-related 403s
- Verify network egress to objects.githubusercontent.com
- Reduce tail_lines to shrink the download window if transfers keep breaking
Example fix
// before
if err != nil {
return err // opaque nested error
}
// after - branch on the wrapped cause
var ghErr *ghErrors.GitHubAPIError
if errors.As(err, &ghErr) && ghErr.Response != nil {
switch ghErr.Response.StatusCode {
case 403:
return retryWithFreshURL() // signed URL expired
case 404:
return fmt.Errorf("log blob gone (expired retention)")
}
} Defensive patterns
Strategy: retry
Validate before calling
// Pre-check egress and freshness before requesting content
if returnContent && !hostReachable("objects.githubusercontent.com") {
return errors.New("blob storage unreachable; use return_content=false for URL only")
} Try / catch
if err != nil {
if strings.Contains(err.Error(), "HTTP 403") {
return retryWithFreshURL() // signed URL expired
}
if strings.Contains(err.Error(), "HTTP 404") {
return err // purged blob: not retryable
}
return retryOnce() // transport/streaming: transient
} Prevention
- Never cache or reuse logs URLs - fetch a fresh one per download
- Open egress to objects.githubusercontent.com where the server runs
- Prefer return_content=false (URL only) when network to blob storage is restricted
- Unwrap nested errors to find the inner download cause
When it happens
Trigger: Calling action_job_logs with return_content=true where the follow-up GET of the signed URL (from the 302 redirect of GetWorkflowJobLogs) fails: network break, expired signed URL returning 403, blob deleted returning 404, or the ring-buffer reader hitting a mid-body error.
Common situations: Delay between getting the signed URL and fetching it (URLs are short-lived); egress blocking objects.githubusercontent.com; large logs cut off by proxies; token has API access but the environment cannot reach GitHub's blob storage.
Related errors
- failed to download logs: HTTP %d
- GitHub App authentication requires a private key: set GITHUB
- GitHub App private key is required (GITHUB_APP_PRIVATE_KEY_P
- no PEM block found in private key
- failed to read log content: %w
AI-assisted analysis of github/github-mcp-server@0ea1f775a7 (2026-08-15).
Data as JSON: /api/errors/4dfdaa761b32c176.
Report an issue: GitHub.