github/github-mcp-server · error

failed to read log content: %w

Error message

failed to read log content: %w

What it means

Wrapped error returned by buffer.ProcessResponseAsRingBufferToEnd when httpResp.Body.Read returns a non-EOF error while the ring buffer streams a GitHub Actions job log line by line (pkg/buffer/buffer.go:113). The %w preserves the underlying transport error, so the real cause (connection reset, TLS failure, context cancellation) stays inspectable. io.EOF is handled separately as normal termination, so this path means the download genuinely broke mid-stream.

Source

Thrown at pkg/buffer/buffer.go:113

				newlineIdx := bytes.IndexByte(chunk, '\n')
				if newlineIdx < 0 {
					accumulate(chunk)
					break
				}
				accumulate(chunk[:newlineIdx])
				storeLine()
				chunk = chunk[newlineIdx+1:]
			}
		}

		if err == io.EOF {
			if currentLine.Len() > 0 {
				storeLine()
			}
			break
		}
		if err != nil {
			return "", 0, httpResp, fmt.Errorf("failed to read log content: %w", err)
		}
	}

	var result []string
	linesInBuffer := min(totalLines, maxJobLogLines)

	startIndex := 0
	if totalLines > maxJobLogLines {
		startIndex = writeIndex
	}

	for i := range linesInBuffer {
		idx := (startIndex + i) % maxJobLogLines
		if validLines[idx] {
			result = append(result, lines[idx])
		}
	}

View on GitHub (pinned to 0ea1f775a7)

Solutions

  1. Retry the tool call - each attempt fetches a fresh signed log URL, and transient body-read breaks usually clear on the second attempt
  2. Pass a smaller tail_lines so the transfer is shorter and less likely to be cut off
  3. Check egress to objects.githubusercontent.com if failures are consistent (proxy, firewall, TLS interception)
  4. Unwrap the error: errors.Is(err, context.Canceled) or context.DeadlineExceeded means the client aborted, not GitHub

Example fix

// before
content, total, resp, err := buffer.ProcessResponseAsRingBufferToEnd(httpResp, tailLines)
if err != nil {
    return "", 0, resp, err
}

// after - separate caller aborts from transient failures
content, total, resp, err := buffer.ProcessResponseAsRingBufferToEnd(httpResp, tailLines)
if err != nil {
    if errors.Is(err, context.Canceled) || errors.Is(err, context.DeadlineExceeded) {
        return "", 0, resp, err // caller aborted: do not retry
    }
    return "", 0, resp, fmt.Errorf("transient log read failure, retry recommended: %w", err)
}
Defensive patterns

Strategy: retry

Validate before calling

// Before requesting log content: ensure the caller context is live and the body exists
if ctx.Err() != nil {
    return ctx.Err() // abort early instead of failing mid-read
}
if httpResp == nil || httpResp.Body == nil {
    return errors.New("no response body to read")
}

Try / catch

if _, _, _, err := buffer.ProcessResponseAsRingBufferToEnd(httpResp, n); err != nil {
    if errors.Is(err, context.Canceled) || errors.Is(err, context.DeadlineExceeded) {
        return err // caller abort: never retry
    }
    // transient body failure: re-fetch a fresh log URL and retry once
    return fetchAndBufferWithRetry(ctx, client, owner, repo, jobID, n, 1)
}

Prevention

When it happens

Trigger: Calling the action_job_logs tool with return_content=true: GetWorkflowJobLogs yields a signed blob URL, downloadLogContent performs http.Get, and ProcessResponseAsRingBufferToEnd reads the body. It fails when the connection is reset mid-download, a proxy/CDN idle timeout fires on a large log, a TLS error occurs, or the caller's context is cancelled while body.Read is blocked.

Common situations: Very large workflow logs (tens of MB) that exceed proxy timeouts; corporate proxies or firewalls killing long-lived downloads from objects.githubusercontent.com; flaky CI networks; user aborting the MCP tool call mid-read.

Related errors


AI-assisted analysis of github/github-mcp-server@0ea1f775a7 (2026-08-15). Data as JSON: /api/errors/e407f365a9c38d55. Report an issue: GitHub.