github/github-mcp-server · warning
GitHub App authentication and GITHUB_PERSONAL_ACCESS_TOKEN a
Error message
GitHub App authentication and GITHUB_PERSONAL_ACCESS_TOKEN are mutually exclusive: set only one
What it means
Raised when json.Marshal(release) fails while serializing the *github.RepositoryRelease returned by GetReleaseByTag into the tool's text result. Go's encoder only errors on values that cannot be represented as JSON: NaN/Inf floats, channels, funcs, or cyclic references. A release struct decoded from GitHub's JSON API cannot contain such values, so this is a defensive invariant that is effectively unreachable in practice.
Source
Thrown at cmd/github-mcp-server/main.go:66
oauthClientID := viper.GetString("oauth-client-id")
oauthClientSecret := viper.GetString("oauth-client-secret")
// Fall back to the build-time baked-in client (official releases) when none is
// configured explicitly. The baked-in app is registered on github.com, so it is
// only applied to the default host; GHES/ghe.com users must bring their own
// --oauth-client-id. Recognizing the host via NormalizeHost means an explicit
// GITHUB_HOST=github.com (or api.github.com) still counts as the default and keeps
// zero-config login working. The secret tracks the id, so an explicitly provided
// id with no secret never picks up the baked-in secret.
if oauthClientID == "" && !appAuthRequested && oauth.NormalizeHost(viper.GetString("host")) == "https://github.com" {
oauthClientID = buildinfo.OAuthClientID
oauthClientSecret = buildinfo.OAuthClientSecret
}
if token == "" && !appAuthRequested && oauthClientID == "" {
return errors.New("authentication required: set GITHUB_PERSONAL_ACCESS_TOKEN, configure GitHub App auth, or pass --oauth-client-id to log in via OAuth")
}
if appAuthRequested && token != "" {
return errors.New("GitHub App authentication and GITHUB_PERSONAL_ACCESS_TOKEN are mutually exclusive: set only one")
}
if appAuthRequested && oauthClientID != "" {
return errors.New("GitHub App authentication and OAuth login (--oauth-client-id) are mutually exclusive: set only one")
}
// If you're wondering why we're not using viper.GetStringSlice("toolsets"),
// it's because viper doesn't handle comma-separated values correctly for env
// vars when using GetStringSlice.
// https://github.com/spf13/viper/issues/380
//
// Additionally, viper.UnmarshalKey returns an empty slice even when the flag
// is not set, but we need nil to indicate "use defaults". So we check IsSet first.
var enabledToolsets []string
if viper.IsSet("toolsets") {
if err := viper.UnmarshalKey("toolsets", &enabledToolsets); err != nil {
return fmt.Errorf("failed to unmarshal toolsets: %w", err)
}
}View on GitHub (pinned to 0ea1f775a7)
Solutions
- Treat it as a bug, not a config issue: capture the tool input (owner/repo/tag) and report it upstream
- Upgrade github-mcp-server and its pinned go-github to matching released versions
- If you maintain a go-github fork, audit added fields for chan/func/float NaN types and implement json.Marshaler for them
Example fix
// before: fork adds an unmarshalable field
type RepositoryRelease struct {
// ...
Done chan struct{} `json:"done"` // json.Marshal errors
}
// after: use a JSON-representable type
type RepositoryRelease struct {
// ...
Done bool `json:"done"`
} Defensive patterns
Strategy: try-catch
Type guard
func isMarshalError(err error) bool {
return err != nil && strings.Contains(err.Error(), "failed to marshal")
} Try / catch
result, _, err := callGetReleaseByTag(ctx, owner, repo, tag)
if err != nil && isMarshalError(err) {
// non-retryable internal invariant: report with inputs, do not loop
log.Printf("marshal bug: owner=%s repo=%s tag=%s err=%v", owner, repo, tag, err)
return err
} Prevention
- Pin github-mcp-server and its go-github dependency to matching released versions
- Do not mutate or extend go-github response structs in forks without json.Marshaler support
- Add a CI round-trip test that marshals the DTOs you rely on
When it happens
Trigger: Only possible if the RepositoryRelease value gains an unmarshalable field: a forked/patched go-github schema adds a chan/func/NaN field, or custom code mutates the struct between fetch and marshal. Stock go-github types decoded from the API never trigger it.
Common situations: Vendored or forked go-github with non-JSON field types; a data race where another goroutine swaps the struct mid-marshal; version skew between github-mcp-server and a patched go-github dependency.
Understand the failure class
- Authentication and authorization failures — expired tokens, bad credentials, and missing scopes.
Related errors
- GitHub App ID or client ID is required (GITHUB_APP_ID)
- repo is required
- failed to marshal response: %w
- failed to marshal workflow: %w
- failed to marshal workflow run: %w
AI-assisted analysis of github/github-mcp-server@0ea1f775a7 (2026-08-15).
Data as JSON: /api/errors/9c60b4af0587e0cc.
Report an issue: GitHub.