github/github-mcp-server · error

requesting installation token: %w

Error message

requesting installation token: %w

What it means

The POST to the access_tokens endpoint failed at the transport level: DNS resolution, TCP connect, TLS handshake, proxy refusal, or the 30-second httpTimeout elapsing (set at internal/githubapp/githubapp.go:31,136). The %w wrap preserves the *url.Error, whose Timeout()/Temporary() methods classify the failure. No HTTP status was received — the response-handling errors (105/106) are separate.

Source

Thrown at internal/githubapp/githubapp.go:149

	endpoint, err := url.JoinPath(s.cfg.BaseRESTURL, "app", "installations", s.cfg.InstallationID, "access_tokens")
	if err != nil {
		return nil, fmt.Errorf("building installation token URL: %w", err)
	}

	ctx, cancel := context.WithTimeout(context.Background(), httpTimeout)
	defer cancel()

	req, err := http.NewRequestWithContext(ctx, http.MethodPost, endpoint, nil)
	if err != nil {
		return nil, fmt.Errorf("creating installation token request: %w", err)
	}
	req.Header.Set("Authorization", "Bearer "+jwt)
	req.Header.Set("Accept", "application/vnd.github+json")
	req.Header.Set("X-GitHub-Api-Version", "2022-11-28")

	resp, err := s.httpClient.Do(req)
	if err != nil {
		return nil, fmt.Errorf("requesting installation token: %w", err)
	}
	defer func() { _ = resp.Body.Close() }()

	if resp.StatusCode != http.StatusCreated {
		snippet, readErr := io.ReadAll(io.LimitReader(resp.Body, 512))
		if readErr != nil {
			return nil, fmt.Errorf("installation token request failed: %s (reading response: %w)", resp.Status, readErr)
		}
		return nil, fmt.Errorf("installation token request failed: %s: %s", resp.Status, strings.TrimSpace(string(snippet)))
	}

	var body struct {
		Token     string    `json:"token"`
		ExpiresAt time.Time `json:"expires_at"`
	}
	if err := json.NewDecoder(resp.Body).Decode(&body); err != nil {
		return nil, fmt.Errorf("decoding installation token response: %w", err)
	}

View on GitHub (pinned to 0ea1f775a7)

Solutions

  1. Check connectivity from the same environment: curl -v -X POST https://api.github.com/app/installations/ID/access_tokens (expect 401, which proves reachability)
  2. If a proxy is required, set HTTPS_PROXY/HTTP_PROXY (and NO_PROXY) in the process environment so Go's default transport uses it
  3. For GHES with private CA, install the CA bundle (SSL_CERT_FILE or system store) — a TLS error appears in the wrapped message
  4. Retry after a short backoff: Provider caches failures only in logs, and the next AccessToken() call re-attempts, so transient outages self-heal
Defensive patterns

Strategy: retry

Validate before calling

// reachability probe before first use (optional, cheap):
//   curl-equivalent: HEAD https://api.github.com/ with the same proxy env
func apiReachable() bool {
    c := &http.Client{Timeout: 5 * time.Second}
    resp, err := c.Head(strings.TrimSuffix(baseRESTURL, "/"))
    return err == nil && resp != nil
}

Try / catch

var ue *url.Error
if errors.As(err, &ue) && ue.Timeout() { /* backoff and retry; Provider re-attempts on next AccessToken() */ }

Prevention

When it happens

Trigger: s.httpClient.Do(req) at internal/githubapp/githubapp.go:147 errors: api.github.com unreachable behind a firewall, corporate proxy env vars (HTTPS_PROXY) pointing at a dead proxy, GHES host with an untrusted TLS cert, DNS failure in the container, or the whole exchange exceeding 30s on a slow link.

Common situations: Container without proxy env vars despite an egress proxy being mandatory; self-signed cert on GitHub Enterprise Server without the CA in the container trust store; transient GitHub API outage; IPv6-only resolution failure; DNS flakiness in Kubernetes pods.

Related errors


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