github/github-mcp-server · error
creating installation token request: %w
Error message
creating installation token request: %w
What it means
http.NewRequestWithContext rejected the endpoint URL built from BaseRESTURL. NewRequestWithContext calls url.Parse on the final joined string, so it fails only when the URL is still unparseable — a base that survived JoinPath but contains characters the stricter request parser rejects, or an empty URL after joining. Like error 102 this is a configuration-shape failure that occurs before any socket is opened.
Source
Thrown at internal/githubapp/githubapp.go:141
}
func (s *installationTokenSource) Token() (*oauth2.Token, error) {
jwt, err := mintJWT(s.cfg.AppID, s.privateKey, time.Now())
if err != nil {
return nil, err
}
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)))
}View on GitHub (pinned to 0ea1f775a7)
Solutions
- Sanitize BaseRESTURL and InstallationID (strip CR/LF/spaces) before building the Config
- Confirm InstallationID is digits-only — GitHub installation IDs are numeric strings
- Validate the final URL with url.ParseRequestURI in a startup check to catch this before first token refresh
Example fix
// before
installationID := rawUserInput // " 42
" -> creating installation token request: ...
// after
installationID := strings.TrimSpace(rawUserInput)
if !regexp.MustCompile(`^[0-9]+$`).MatchString(installationID) {
return errors.New("installation ID must be numeric")
} Defensive patterns
Strategy: validation
Validate before calling
func validInstallationID(s string) bool { return regexp.MustCompile(`^[0-9]+$`).MatchString(s) }
// and before building Config:
if _, err := url.ParseRequestURI(base); err != nil { return err } Prevention
- Treat installation IDs as numeric-only at every input boundary (flags, env, config files)
- Strip CR/LF from config values loaded from Windows-authored files
When it happens
Trigger: The joined endpoint string (e.g. BaseRESTURL + 'app/installations/{id}/access_tokens') contains a control character (0x7f, raw newline), a space in the host, or InstallationID text that makes the path invalid, causing http.NewRequestWithContext at internal/githubapp/githubapp.go:139 to return a parse error.
Common situations: BaseRESTURL loaded from a .env file with embedded CR ( ) from Windows line endings; an InstallationID taken from user input containing spaces or '%zz' malformed escapes; a config value that is actually empty after JoinPath normalization.
Related errors
- building installation token URL: %w
- could not parse host as URL: %s
- unknown tools specified in WithTools
- failed to unmarshal toolsets: %w
- failed to unmarshal tools: %w
AI-assisted analysis of github/github-mcp-server@0ea1f775a7 (2026-08-15).
Data as JSON: /api/errors/c6581794b8769023.
Report an issue: GitHub.