github/github-mcp-server · error · ErrBadRequest
bad request
Error message
bad request
What it means
ErrBadRequest is a generic 'mark' sentinel in pkg/http/mark used to classify client-side request errors. The mark package itself never throws it on its own; concrete errors wrap it via mark.With or fmt.Errorf('%w: ...'), and calling code detects it with errors.Is. In this codebase the primary producers are pkg/utils/token.go's Authorization header errors: missing header, badly formatted header, or unsupported scheme/token.
Source
Thrown at pkg/http/mark/mark.go:23
// This list of errors is not exhaustive, but is a good starting point for most
// applications. Feel free to add more as needed, but don't go overboard.
// Remember, the specific types of errors are only important so far as someone
// calling your code might want to write logic to handle each type of error
// differently.
//
// Do not add application-specific errors to this list. Instead, just define
// your own package with your own application-specific errors, and use this
// package to mark errors with them. The errors in this package are not special,
// they're just plain old errors.
//
// Not all errors need to be marked. An error that is not marked should be
// treated as an unexpected error that cannot be handled by calling code. This
// is often the case for network errors or logic errors.
var (
ErrNotFound = errors.New("not found")
ErrAlreadyExists = errors.New("already exists")
ErrBadRequest = errors.New("bad request")
ErrUnauthorized = errors.New("unauthorized")
ErrCancelled = errors.New("request cancelled")
ErrUnavailable = errors.New("unavailable")
ErrTimedout = errors.New("request timed out")
ErrTooLarge = errors.New("request is too large")
ErrTooManyRequests = errors.New("too many requests")
ErrForbidden = errors.New("forbidden")
)
// With wraps err with another error that will return true from errors.Is and
// errors.As for both err and markErr, and anything either may wrap.
func With(err, markErr error) error {
if err == nil {
return nil
}
return marked{wrapped: err, mark: markErr}
}
View on GitHub (pinned to 0ea1f775a7)
Solutions
- Send a valid GitHub token: 'Authorization: Bearer ghp_...' (classic PAT), github_pat_... (fine-grained), gho_/ghu_/ghs_ (OAuth/App tokens)
- If a proxy fronts the server, ensure it forwards the Authorization header unmodified
- If you must accept non-GitHub tokens, wrap the server with your own auth layer rather than relying on ParseAuthorizationHeader
- On the server side, map errors.Is(err, mark.ErrBadRequest) to an HTTP 400 response with the wrapped detail
Example fix
// client: before
req.Header.Set("Authorization", token) // raw token or wrong scheme
// client: after
req.Header.Set("Authorization", "Bearer "+githubToken) // ghp_..., github_pat_..., gho_..., ghu_..., ghs_... Defensive patterns
Strategy: validation
Validate before calling
// Client-side: build a correctly formed header before sending
validPrefixes := []string{"ghp_", "github_pat_", "gho_", "ghu_", "ghs_"}
isGitHubToken := func(tok string) bool {
for _, p := range validPrefixes {
if strings.HasPrefix(tok, p) {
return true
}
}
return regexp.MustCompile(`^[a-f0-9]{40}$`).MatchString(tok) // legacy PAT
}
if !isGitHubToken(token) {
return errors.New("token is not a GitHub token; get one at github.com/settings/tokens")
}
req.Header.Set("Authorization", "Bearer "+token) Type guard
// errors.Is narrows any wrapped cause back to the bad-request mark
func isBadRequest(err error) bool {
return err != nil && errors.Is(err, mark.ErrBadRequest)
} Try / catch
// Server-side: map the mark to HTTP 400 with the wrapped detail
if err := utils.ParseAuthorizationHeader(req); err != nil {
if errors.Is(err, mark.ErrBadRequest) {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
http.Error(w, "internal error", http.StatusInternalServerError)
} Prevention
- Always send 'Authorization: Bearer <github-token>' with one of the ghp_/github_pat_/gho_/ghu_/ghs_ prefixes
- Never send 'GitHub-Bearer' headers — explicitly unsupported
- Verify proxies forward Authorization headers unmodified
- Check errors.Is(err, mark.ErrBadRequest) to distinguish client errors from server failures
When it happens
Trigger: Calling the remote/HTTP server endpoints without an Authorization header (ErrMissingAuthorizationHeader); sending a token GitHub does not recognize (no ghp_/github_pat_/gho_/ghu_/ghs_ prefix and not a legacy 40-char hex token) yielding ErrBadAuthorizationHeader; sending a 'GitHub-Bearer ...' header, which is explicitly rejected as ErrUnsupportedAuthorizationHeader.
Common situations: Using the remote GitHub MCP server behind a proxy that strips Authorization headers; passing an opaque proxy token or JWT where a GitHub token is required; legacy deployments sending dotcom encrypted tokens; clients omitting the 'Bearer ' prefix in ways that alter the parsed token value.
Related errors
- %w: Authorization header is badly formatted
- bad request: Authorization header is badly formatted
- bad request: unsupported Authorization header
- App not connected
- %w: missing required Authorization header
AI-assisted analysis of github/github-mcp-server@0ea1f775a7 (2026-08-15).
Data as JSON: /api/errors/6958645e5f91aa70.
Report an issue: GitHub.