{"record":{"id":"f1b622a1dc68f35e","repo":"github/github-mcp-server","slug":"building-installation-token-url-w","errorCode":null,"errorMessage":"building installation token URL: %w","messagePattern":"building installation token URL: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/githubapp/githubapp.go","lineNumber":133,"sourceCode":"\thttpClient *http.Client\n}\n\nfunc newInstallationTokenSource(cfg Config, privateKey *rsa.PrivateKey, httpClient *http.Client) *installationTokenSource {\n\tif httpClient == nil {\n\t\thttpClient = &http.Client{Timeout: httpTimeout}\n\t}\n\treturn &installationTokenSource{cfg: cfg, privateKey: privateKey, httpClient: httpClient}\n}\n\nfunc (s *installationTokenSource) Token() (*oauth2.Token, error) {\n\tjwt, err := mintJWT(s.cfg.AppID, s.privateKey, time.Now())\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tendpoint, err := url.JoinPath(s.cfg.BaseRESTURL, \"app\", \"installations\", s.cfg.InstallationID, \"access_tokens\")\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"building installation token URL: %w\", err)\n\t}\n\n\tctx, cancel := context.WithTimeout(context.Background(), httpTimeout)\n\tdefer cancel()\n\n\treq, err := http.NewRequestWithContext(ctx, http.MethodPost, endpoint, nil)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"creating installation token request: %w\", err)\n\t}\n\treq.Header.Set(\"Authorization\", \"Bearer \"+jwt)\n\treq.Header.Set(\"Accept\", \"application/vnd.github+json\")\n\treq.Header.Set(\"X-GitHub-Api-Version\", \"2022-11-28\")\n\n\tresp, err := s.httpClient.Do(req)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"requesting installation token: %w\", err)\n\t}\n\tdefer func() { _ = resp.Body.Close() }()","sourceCodeStart":115,"sourceCodeEnd":151,"githubUrl":"https://github.com/github/github-mcp-server/blob/0ea1f775a7c73eff1bd2e25904d01136756bbfe2/internal/githubapp/githubapp.go#L115-L151","documentation":"url.JoinPath returned an error while composing {BaseRESTURL}/app/installations/{id}/access_tokens. JoinPath parses BaseRESTURL first, so this fires when the configured base is not a valid absolute URL — typically a missing scheme or illegal control characters. It is a configuration error in Config.BaseRESTURL, not a network problem.","triggerScenarios":"Config.BaseRESTURL is set to 'api.github.com' (no https:// scheme), to 'https://api.github.com\\n' with a trailing newline from an env var, or contains a control character. url.JoinPath(s.cfg.BaseRESTURL, ...) at internal/githubapp/githubapp.go:131 fails during parsing before any HTTP traffic occurs, so Token() fails immediately on the first call.","commonSituations":"GITHUB_API_URL or the equivalent env var populated by a script that strips the scheme; GitHub Enterprise Server base like 'https://ghe.example.com/api/v3' mistyped as 'ghe.example.com/api/v3'; YAML/JSON config values carrying stray quotes, backslashes, or CRLF.","solutions":["Set BaseRESTURL with an explicit scheme: https://api.github.com/ for github.com, https://HOST/api/v3/ for GitHub Enterprise Server","Trim whitespace/newlines when loading the value from env or config files","Validate the URL at startup with url.Parse and check .IsAbs() before constructing the provider"],"exampleFix":"// before\ncfg := githubapp.Config{BaseRESTURL: os.Getenv(\"GH_API_URL\"), ...} // \"ghe.example.com/api/v3\"\n\n// after\nbase := strings.TrimSpace(os.Getenv(\"GH_API_URL\"))\nif u, err := url.Parse(base); err != nil || !u.IsAbs() {\n    return fmt.Errorf(\"BaseRESTURL %q must be an absolute URL\", base)\n}\ncfg := githubapp.Config{BaseRESTURL: base, ...}","handlingStrategy":"validation","validationCode":"func validBaseRESTURL(s string) error {\n    u, err := url.Parse(strings.TrimSpace(s))\n    if err != nil {\n        return err\n    }\n    if !u.IsAbs() || u.Host == \"\" {\n        return fmt.Errorf(\"%q must be absolute, e.g. https://api.github.com/\", s)\n    }\n    return nil\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Normalize env-sourced URLs with strings.TrimSpace before use","Standardize on https://api.github.com/ and https://HOST/api/v3/ via a shared config helper"],"tags":["configuration","url","github-enterprise","startup"],"backgroundTag":null,"analyzedSha":"0ea1f775a7c73eff1bd2e25904d01136756bbfe2","analyzedAt":"2026-08-15T18:10:19.804Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}