{"record":{"id":"4f417ea8e86cc7d2","repo":"git-ecosystem/git-credential-manager","slug":"user-cancelled-dialog-4f417e","errorCode":null,"errorMessage":"User cancelled dialog.","messagePattern":"User cancelled dialog\\.","errorType":"exception","errorClass":"Trace2Exception","httpStatus":null,"severity":"info","filePath":"src/Core/UI/Commands/DeviceCodeCommand.cs","lineNumber":39,"sourceCode":"\n            this.SetHandler(ExecuteAsync, code, url, noLogo);\n        }\n\n        private async Task<int> ExecuteAsync(string code, string url, bool noLogo)\n        {\n            var viewModel = new DeviceCodeViewModel(Context.SessionManager)\n            {\n                UserCode = code,\n                VerificationUrl = url,\n            };\n\n            viewModel.ShowProductHeader = !noLogo;\n\n            await ShowAsync(viewModel, CancellationToken.None);\n\n            if (!viewModel.WindowResult)\n            {\n                throw new Trace2Exception(Context.Trace2, \"User cancelled dialog.\");\n            }\n\n            return 0;\n        }\n\n        protected abstract Task ShowAsync(DeviceCodeViewModel viewModel, CancellationToken ct);\n    }\n}\n","sourceCodeStart":21,"sourceCodeEnd":48,"githubUrl":"https://github.com/git-ecosystem/git-credential-manager/blob/e8ce762cd04b4100ae637b5fbf39ef9d0a96561e/src/Core/UI/Commands/DeviceCodeCommand.cs#L21-L48","documentation":"Thrown by DeviceCodeCommand.ExecuteAsync when the device-code dialog is dismissed without confirmation. The abstract ShowAsync presents the device-code UI; if the user closes it, WindowResult is false and the command throws instead of returning a result. This is a deliberate cancellation signal surfaced through Trace2 tracing.","triggerScenarios":"Executing the device-code authentication command; the user closes the device-code window, hits Cancel/Esc, or the dialog fails to submit before ShowAsync returns with WindowResult == false.","commonSituations":"CI jobs with no interactive user show the dialog and it gets dismissed or orphaned; users close the window thinking it is not needed; automation frameworks kill the dialog window.","solutions":["Catch the Trace2Exception and handle it as a cancellation (return a cancelled exit code)","Avoid showing the dialog in non-interactive environments (set GCM_INTERACTIVE=never or equivalent)","Use a non-interactive authentication mode such as PAT via environment variables or credential store instead of the device-code UI","Complete the device-code flow in the dialog instead of closing it"],"exampleFix":"// before\nawait command.ExecuteAsync();\n// after\ntry { await command.ExecuteAsync(); }\ncatch (Trace2Exception ex) when (ex.Message.Contains(\"cancelled\"))\n{\n    return ExitCode.Cancelled; // user closed the device-code dialog\n}","handlingStrategy":"try-catch","validationCode":"// Skip the device-code UI when no interactive session is available\nif (!Environment.UserInteractive || Environment.GetEnvironmentVariable(\"GCM_INTERACTIVE\") == \"never\")\n{\n    throw new InvalidOperationException(\"Device-code flow requires an interactive session; use a PAT instead.\");\n}","typeGuard":null,"tryCatchPattern":"try\n{\n    await deviceCodeCommand.ExecuteAsync();\n}\ncatch (Trace2Exception ex) when (ex.Message.Contains(\"User cancelled dialog\"))\n{\n    return ExitCode.Cancelled;\n}","preventionTips":["Use PAT or credential-store authentication in headless environments instead of device-code UI","Always catch the cancellation exception so scripts exit cleanly instead of crashing","Complete the device-code flow promptly; closing the window cancels the operation","Keep GCM updated so the device dialog behaves consistently"],"tags":["ui","dialog","cancellation","device-code","oauth"],"backgroundTag":"user-cancelled-dialog","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"}