github/github-mcp-server · error
failed to create REST client: %w
Error message
failed to create REST client: %w
What it means
GetClient builds the REST client via gogithub.NewClient(WithAuthToken, WithUserAgent, WithEnterpriseURLs(baseRestURL.String(), uploadURL.String())). WithEnterpriseURLs re-parses both URL strings with url.Parse and checks they are absolute; any string the resolver produced that go-github cannot parse becomes this wrapped error. Because the strings come from already-parsed *url.URL values, it is nearly unreachable in the standard wiring and signals a malformed or nil-derived URL in a custom resolver.
Source
Thrown at pkg/github/dependencies.go:332
token := tokenInfo.Token
baseRestURL, err := d.apiHosts.BaseRESTURL(ctx)
if err != nil {
return nil, fmt.Errorf("failed to get base REST URL: %w", err)
}
uploadURL, err := d.apiHosts.UploadURL(ctx)
if err != nil {
return nil, fmt.Errorf("failed to get upload URL: %w", err)
}
// Construct REST client
restClient, err := gogithub.NewClient(
gogithub.WithAuthToken(token),
gogithub.WithUserAgent(fmt.Sprintf("github-mcp-server/%s", d.version)),
gogithub.WithEnterpriseURLs(baseRestURL.String(), uploadURL.String()),
)
if err != nil {
return nil, fmt.Errorf("failed to create REST client: %w", err)
}
return restClient, nil
}
// GetGQLClient implements ToolDependencies.
func (d *RequestDeps) GetGQLClient(ctx context.Context) (*githubv4.Client, error) {
// extract the token from the context
tokenInfo, ok := ghcontext.GetTokenInfo(ctx)
if !ok {
return nil, fmt.Errorf("no token info in context")
}
token := tokenInfo.Token
// Construct GraphQL client
// We use NewEnterpriseClient unconditionally since we already parsed the API host
// Wrap transport with GraphQLFeaturesTransport to inject feature flags from context,
// matching the transport chain used by the remote server.
gqlHTTPClient := &http.Client{View on GitHub (pinned to 0ea1f775a7)
Solutions
- Inspect the wrapped error: it is the verbatim go-github/url error and names which URL string failed to parse
- Ensure the resolver returns absolute https URLs (scheme + host), e.g. https://api.github.com/ and https://uploads.github.com
- Reproduce outside the server: url.Parse(baseRestURL.String()) and url.Parse(uploadURL.String()) in a scratch test to find the malformed component
- Percent-encode any tenant or user-supplied path segments before building the URL instead of raw concatenation
- Pin/align the go-github version (v89 in this module) so WithEnterpriseURLs validation matches what you tested
Example fix
// before: concatenating an unvalidated host into a URL
restURL := &url.URL{Scheme: "https", Opaque: host + "/api/v3/"} // Opaque stringifies badly
client, err := gogithub.NewClient(gogithub.WithEnterpriseURLs(restURL.String(), uploadURL.String()))
// after: build via structured fields so String() is always parseable
u := &url.URL{Scheme: "https", Host: host, Path: "/api/v3/"}
if err := validateAbsolute(u); err != nil { return nil, err }
client, err := gogithub.NewClient(gogithub.WithEnterpriseURLs(u.String(), upload.String())) Defensive patterns
Strategy: validation
Validate before calling
// verify both strings are parseable absolute URLs before client construction
for _, s := range []string{baseRestURL.String(), uploadURL.String()} {
u, err := url.Parse(s)
if err != nil || !u.IsAbs() {
return fmt.Errorf("unusable URL for go-github: %q", s)
}
} Type guard
func isAbsoluteURL(s string) bool {
u, err := url.Parse(s)
return err == nil && u.IsAbs() && u.Host != ""
} Try / catch
// in GetClient-style code
restClient, err := gogithub.NewClient(opts...)
if err != nil {
return nil, fmt.Errorf("failed to create REST client: %w", err) // inspect wrapped url.Error via errors.Unwrap
} Prevention
- Build *url.URL via structured fields (Scheme/Host/Path), never string concatenation
- Percent-encode tenant-supplied path segments
- Keep go-github version pinned to the one you tested (v89 here)
When it happens
Trigger: A custom APIHostResolver whose URL objects stringify to relative or control-character-laden URLs (e.g. "/api/v3/" with no scheme, or a URL built from unescaped user input); baseRestURL or uploadURL being nil, panicking before this line, in careless implementations; version drift where WithEnterpriseURLs adds new validation. go-github returns url.Parse errors or 'invalid URL' style errors here.
Common situations: Hand-rolled resolvers that construct URLs via string concatenation with unencoded paths; GHES hosts containing spaces or unicode in the hostname; mixed go-github versions after upgrading v89 where URL validation tightened; resolvers that return *url.URL values reconstructed from tenant-supplied headers.
Related errors
- failed to create raw client: %w
- failed to get base REST URL: %w
- GitHub App authentication and GITHUB_PERSONAL_ACCESS_TOKEN a
- GitHub App authentication and OAuth login (--oauth-client-id
- GitHub App authentication requires a private key: set GITHUB
AI-assisted analysis of github/github-mcp-server@0ea1f775a7 (2026-08-15).
Data as JSON: /api/errors/32ae9aaef0702a6d.
Report an issue: GitHub.