github/github-mcp-server · warning
GitHub App private key is required (GITHUB_APP_PRIVATE_KEY_P
Error message
GitHub App private key is required (GITHUB_APP_PRIVATE_KEY_PATH or GITHUB_APP_PRIVATE_KEY)
What it means
Activity.Star returns 204 No Content on success; on any other status (404 repo not found, 401, 403) the handler reads resp.Body with io.ReadAll to build the status error. This error means that read failed - a transport fault after the status line arrived, which discards the real API error message. Mid-body connection resets, proxy stream closes, and consumed bodies are the usual causes.
Source
Thrown at internal/githubapp/githubapp.go:57
// InstallationID identifies the installation whose access token is minted.
InstallationID string
// PrivateKeyPEM is the RSA key used to sign app JWTs.
PrivateKeyPEM []byte
// BaseRESTURL is the REST API base, e.g. https://api.github.com/ for
// github.com or https://HOST/api/v3/ for GitHub Enterprise Server.
BaseRESTURL string
}
func (c Config) validate() error {
switch {
case c.AppID == "":
return errors.New("GitHub App ID or client ID is required (GITHUB_APP_ID)")
case c.InstallationID == "":
return errors.New("GitHub App installation ID is required (GITHUB_APP_INSTALLATION_ID)")
case len(c.PrivateKeyPEM) == 0:
return errors.New("GitHub App private key is required (GITHUB_APP_PRIVATE_KEY_PATH or GITHUB_APP_PRIVATE_KEY)")
case c.BaseRESTURL == "":
return errors.New("GitHub App REST base URL is required")
}
return nil
}
func parsePrivateKey(pemBytes []byte) (*rsa.PrivateKey, error) {
block, _ := pem.Decode(pemBytes)
if block == nil {
return nil, errors.New("no PEM block found in private key")
}
if key, err := x509.ParsePKCS1PrivateKey(block.Bytes); err == nil {
return key, nil
}
parsed, err := x509.ParsePKCS8PrivateKey(block.Bytes)
if err != nil {
return nil, fmt.Errorf("parsing private key (want PKCS#1 or PKCS#8 RSA): %w", err)
}View on GitHub (pinned to 0ea1f775a7)
Solutions
- Retry star_repository once - starring is idempotent (204 whether newly starred or already starred)
- Verify owner/repo spelling separately, since 404 is the most common non-204 cause
- Stabilize proxy/LB idle timeouts if the failure recurs
- Log the pre-read status code to separate API errors from transport drops
Example fix
// before: single attempt fails at body read
err := starRepo(ctx, owner, repo)
// after: bounded retry; star is idempotent so a repeat is safe
err := starRepo(ctx, owner, repo)
if isBodyReadError(err) {
time.Sleep(250 * time.Millisecond)
err = starRepo(ctx, owner, repo)
} Defensive patterns
Strategy: retry
Type guard
func isBodyReadError(err error) bool {
return err != nil && strings.Contains(err.Error(), "failed to read response body")
} Try / catch
// star_repository is idempotent (204 whether newly starred or not).
err := starRepo(ctx, owner, repo)
if isBodyReadError(err) {
time.Sleep(250 * time.Millisecond)
err = starRepo(ctx, owner, repo)
} Prevention
- Rely on the 204 idempotency: a retried star never double-stars
- Verify owner/repo spelling before bulk star runs to avoid 404 bodies
- Keep star loops on stable network paths; cap retries at 1-2
- Log status codes to tell genuine API errors from transport drops
When it happens
Trigger: Star replies 404 (owner/repo does not exist) and the connection drops before the error body finishes; a proxy resets the stream; keep-alive race between status and body.
Common situations: Scripted starring loops over flaky networks; VPN/proxy instability; LB connection reaping under load.
Related errors
- GitHub App authentication requires a private key: set GITHUB
- no PEM block found in private key
- failed to read log content: %w
- failed to read response body: %w
- failed to read response body: %w
AI-assisted analysis of github/github-mcp-server@0ea1f775a7 (2026-08-15).
Data as JSON: /api/errors/11938e7dec3cbca7.
Report an issue: GitHub.