{"record":{"id":"c475d42201cbb72b","repo":"git-ecosystem/git-credential-manager","slug":"browser-authentication-requires-a-desktop-session-c475d4","errorCode":null,"errorMessage":"Browser authentication requires a desktop session","messagePattern":"Browser authentication requires a desktop session","errorType":"exception","errorClass":"Trace2InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/GitHub/GitHubAuthentication.cs","lineNumber":418,"sourceCode":"\n            if (!resultDict.TryGetValue(\"code\", out string authCode))\n            {\n                throw new Trace2Exception(Context.Trace2, \"Missing 'code' in response\");\n            }\n\n            return authCode;\n        }\n\n        public async Task<OAuth2TokenResult> GetOAuthTokenViaBrowserAsync(Uri targetUri, IEnumerable<string> scopes, string loginHint)\n        {\n            ThrowIfUserInteractionDisabled();\n\n            var oauthClient = new GitHubOAuth2Client(HttpClient, Context.Settings, targetUri, Context.Trace2);\n\n            // Can we launch the user's default web browser?\n            if (!Context.SessionManager.IsWebBrowserAvailable)\n            {\n                throw new Trace2InvalidOperationException(Context.Trace2,\n                    \"Browser authentication requires a desktop session\");\n            }\n\n            var browserOptions = new OAuth2WebBrowserOptions\n            {\n                SuccessResponseHtml = GitHubResources.AuthenticationResponseSuccessHtml,\n                FailureResponseHtmlFormat = GitHubResources.AuthenticationResponseFailureHtmlFormat\n            };\n            var browser = new OAuth2SystemWebBrowser(Context.SessionManager, browserOptions);\n\n            // If we have a login hint we should pass this to GitHub as an extra query parameter\n            IDictionary<string, string> queryParams = null;\n            if (loginHint != null)\n            {\n                queryParams = new Dictionary<string, string>\n                {\n                    [\"login\"] = loginHint\n                };","sourceCodeStart":400,"sourceCodeEnd":436,"githubUrl":"https://github.com/git-ecosystem/git-credential-manager/blob/e8ce762cd04b4100ae637b5fbf39ef9d0a96561e/src/GitHub/GitHubAuthentication.cs#L400-L436","documentation":"Git Credential Manager's browser (OAuth2) authentication flow for GitHub requires the ability to launch the user's default web browser. Before starting the flow, GetOAuthTokenViaBrowserAsync checks Context.SessionManager.IsWebBrowserAvailable, and if the process is running headless (no desktop session / no discoverable browser) it throws this Trace2InvalidOperationException instead of attempting an impossible browser launch.","triggerScenarios":"Calling GetOAuthTokenViaBrowserAsync (e.g. via 'git-credential-manager github login --browser' or GCM choosing Browser auth) on a machine where IsWebBrowserAvailable is false: SSH sessions, CI runners, containers, Windows/SSH servers without a GUI, or environments where SessionManager cannot detect a desktop session.","commonSituations":"Running git push/pull with GCM over SSH into a headless Linux box; CI pipelines that force browser auth instead of PAT/OAuth-device; Docker containers performing credential acquisition interactively; WSL configurations without a browser forwarding setup.","solutions":["Use a non-browser authentication mode instead: a Personal Access Token (GCM_AUTH_PAT / 'git-credential-manager github login --pat') or device-code flow.","Run the git/GCM command inside a desktop session where a default browser is registered and detectable.","Set GCM_INTERACTIVE (or GcmInteractive) to false so GCM picks a non-interactive flow, or pre-seed credentials in the store.","If on WSL/headless, configure the environment so a browser can be opened (e.g. wslu/browser wrapper) or forward credentials from the Windows host."],"exampleFix":"// before\ngit-credential-manager github login --browser   // on headless CI runner\n\n// after\ngit-credential-manager github login --pat      // or set GITHUB_TOKEN / use device flow","handlingStrategy":"validation","validationCode":"if (Environment.UserInteractive == false || string.IsNullOrEmpty(Environment.GetEnvironmentVariable(\"DISPLAY\")) && Environment.OSVersion.Platform != PlatformID.Win32NT)\n{\n    // fall back to PAT or device-code flow instead of browser auth\n    return AuthenticateViaPatOrDeviceCode();\n}","typeGuard":null,"tryCatchPattern":"try\n{\n    var token = await githubAuth.GetOAuthTokenViaBrowserAsync(targetUri, scopes);\n}\ncatch (InvalidOperationException ex) when (ex.Message.Contains(\"desktop session\"))\n{\n    token = await githubAuth.GetOAuthTokenViaDeviceCodeAsync(targetUri, scopes);\n}","preventionTips":["Check for a desktop session/browser availability before choosing browser auth","Default to PAT or device-code auth in CI, containers, and SSH environments","Set GCM_INTERACTIVE=Never in headless automation","Pre-seed credentials with 'git credential approve' for non-interactive runs"],"tags":["github","oauth","authentication","headless-environment"],"backgroundTag":"unsupported-platform","analyzedSha":"e8ce762cd04b4100ae637b5fbf39ef9d0a96561e","analyzedAt":"2026-09-11T17:15:08.753Z","contentChangedAt":"2026-09-11T17:15:08.753Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}