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

  1. Treat it as a bug, not a config issue: capture the tool input (owner/repo/tag) and report it upstream
  2. Upgrade github-mcp-server and its pinned go-github to matching released versions
  3. 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

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

Related errors


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