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

  1. Send a valid GitHub token: 'Authorization: Bearer ghp_...' (classic PAT), github_pat_... (fine-grained), gho_/ghu_/ghs_ (OAuth/App tokens)
  2. If a proxy fronts the server, ensure it forwards the Authorization header unmodified
  3. If you must accept non-GitHub tokens, wrap the server with your own auth layer rather than relying on ParseAuthorizationHeader
  4. 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

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


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