{"record":{"id":"9c60b4af0587e0cc","repo":"github/github-mcp-server","slug":"github-app-authentication-and-github-personal-acce","errorCode":null,"errorMessage":"GitHub App authentication and GITHUB_PERSONAL_ACCESS_TOKEN are mutually exclusive: set only one","messagePattern":"GitHub App authentication and GITHUB_PERSONAL_ACCESS_TOKEN are mutually exclusive: set only one","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"cmd/github-mcp-server/main.go","lineNumber":66,"sourceCode":"\n\t\t\toauthClientID := viper.GetString(\"oauth-client-id\")\n\t\t\toauthClientSecret := viper.GetString(\"oauth-client-secret\")\n\t\t\t// Fall back to the build-time baked-in client (official releases) when none is\n\t\t\t// configured explicitly. The baked-in app is registered on github.com, so it is\n\t\t\t// only applied to the default host; GHES/ghe.com users must bring their own\n\t\t\t// --oauth-client-id. Recognizing the host via NormalizeHost means an explicit\n\t\t\t// GITHUB_HOST=github.com (or api.github.com) still counts as the default and keeps\n\t\t\t// zero-config login working. The secret tracks the id, so an explicitly provided\n\t\t\t// id with no secret never picks up the baked-in secret.\n\t\t\tif oauthClientID == \"\" && !appAuthRequested && oauth.NormalizeHost(viper.GetString(\"host\")) == \"https://github.com\" {\n\t\t\t\toauthClientID = buildinfo.OAuthClientID\n\t\t\t\toauthClientSecret = buildinfo.OAuthClientSecret\n\t\t\t}\n\t\t\tif token == \"\" && !appAuthRequested && oauthClientID == \"\" {\n\t\t\t\treturn errors.New(\"authentication required: set GITHUB_PERSONAL_ACCESS_TOKEN, configure GitHub App auth, or pass --oauth-client-id to log in via OAuth\")\n\t\t\t}\n\t\t\tif appAuthRequested && token != \"\" {\n\t\t\t\treturn errors.New(\"GitHub App authentication and GITHUB_PERSONAL_ACCESS_TOKEN are mutually exclusive: set only one\")\n\t\t\t}\n\t\t\tif appAuthRequested && oauthClientID != \"\" {\n\t\t\t\treturn errors.New(\"GitHub App authentication and OAuth login (--oauth-client-id) are mutually exclusive: set only one\")\n\t\t\t}\n\n\t\t\t// If you're wondering why we're not using viper.GetStringSlice(\"toolsets\"),\n\t\t\t// it's because viper doesn't handle comma-separated values correctly for env\n\t\t\t// vars when using GetStringSlice.\n\t\t\t// https://github.com/spf13/viper/issues/380\n\t\t\t//\n\t\t\t// Additionally, viper.UnmarshalKey returns an empty slice even when the flag\n\t\t\t// is not set, but we need nil to indicate \"use defaults\". So we check IsSet first.\n\t\t\tvar enabledToolsets []string\n\t\t\tif viper.IsSet(\"toolsets\") {\n\t\t\t\tif err := viper.UnmarshalKey(\"toolsets\", &enabledToolsets); err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"failed to unmarshal toolsets: %w\", err)\n\t\t\t\t}\n\t\t\t}","sourceCodeStart":48,"sourceCodeEnd":84,"githubUrl":"https://github.com/github/github-mcp-server/blob/0ea1f775a7c73eff1bd2e25904d01136756bbfe2/cmd/github-mcp-server/main.go#L48-L84","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before: fork adds an unmarshalable field\ntype RepositoryRelease struct {\n\t// ...\n\tDone chan struct{} `json:\"done\"` // json.Marshal errors\n}\n\n// after: use a JSON-representable type\ntype RepositoryRelease struct {\n\t// ...\n\tDone bool `json:\"done\"`\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":"func isMarshalError(err error) bool {\n\treturn err != nil && strings.Contains(err.Error(), \"failed to marshal\")\n}","tryCatchPattern":"result, _, err := callGetReleaseByTag(ctx, owner, repo, tag)\nif err != nil && isMarshalError(err) {\n\t// non-retryable internal invariant: report with inputs, do not loop\n\tlog.Printf(\"marshal bug: owner=%s repo=%s tag=%s err=%v\", owner, repo, tag, err)\n\treturn err\n}","preventionTips":["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"],"tags":["go","json","serialization","defensive"],"backgroundTag":null,"analyzedSha":"0ea1f775a7c73eff1bd2e25904d01136756bbfe2","analyzedAt":"2026-08-15T18:10:19.804Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}