{"record":{"id":"3ba6b2ca229738dc","repo":"git-ecosystem/git-credential-manager","slug":"helper-error-exitcode-errormessage","errorCode":null,"errorMessage":"helper error ({exitCode}): {errorMessage}","messagePattern":"helper error \\((.+?)\\): (.+?)","errorType":"exception","errorClass":"Trace2Exception","httpStatus":null,"severity":"error","filePath":"src/Core/Authentication/AuthenticationBase.cs","lineNumber":80,"sourceCode":"            if (standardInput is not null)\n            {\n                await standardInput.BaseStream.CopyToAsync(process.StandardInput.BaseStream, ct);\n                process.StandardInput.Close();\n            }\n\n            IDictionary<string, string> resultDict = await process.StandardOutput.ReadDictionaryAsync(StringComparer.OrdinalIgnoreCase);\n\n            await Task.Run(() => process.WaitForExit(), ct);\n            int exitCode = process.ExitCode;\n\n            if (exitCode != 0)\n            {\n                if (!resultDict.TryGetValue(\"error\", out string errorMessage))\n                {\n                    errorMessage = \"Unknown\";\n                }\n\n                throw new Trace2Exception(Context.Trace2, $\"helper error ({exitCode}): {errorMessage}\");\n            }\n\n            return resultDict;\n        }\n\n        protected void ThrowIfUserInteractionDisabled()\n        {\n            if (!Context.Settings.IsInteractionAllowed)\n            {\n                string envName = Constants.EnvironmentVariables.GcmInteractive;\n                string cfgName = string.Format(\"{0}.{1}\",\n                    Constants.GitConfiguration.Credential.SectionName,\n                    Constants.GitConfiguration.Credential.Interactive);\n\n                Context.Trace.WriteLine($\"{envName} / {cfgName} is false/never; user interactivity has been disabled.\");\n                throw new Trace2InvalidOperationException(Context.Trace2, \"Cannot prompt because user interactivity has been disabled.\");\n            }\n        }","sourceCodeStart":62,"sourceCodeEnd":98,"githubUrl":"https://github.com/git-ecosystem/git-credential-manager/blob/e8ce762cd04b4100ae637b5fbf39ef9d0a96561e/src/Core/Authentication/AuthenticationBase.cs#L62-L98","documentation":"After InvokeHelperAsync runs the UI helper, it parses the helper's JSON stdout and exit code. A non-zero exit code means the helper itself failed; GCM throws a Trace2Exception embedding the exit code and the \"error\" field from the helper's output dict (or \"Unknown\" if absent).","triggerScenarios":"The spawned UI helper process exits non-zero with a JSON body containing an \"error\" key (or none), during any flow routed through InvokeHelperAsync (OAuth, account picker, etc.).","commonSituations":"Helper crashed or user aborted in an unexpected way; helper failed OAuth token exchange; platform-specific helper bugs; corrupted helper output causing misparse.","solutions":["Read the errorMessage in the exception — it carries the helper's own error reason.","Re-run with trace2/GCM tracing enabled (GCM_TRACE=1, GIT_TRACE2) to capture the helper's diagnostics.","If the helper consistently fails, reinstall GCM or fall back to a different credential mode (PAT/basic via config)."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try { var dict = await InvokeHelperAsync(...); } catch (Trace2Exception ex) when (ex.Message.StartsWith(\"helper error (\")) { /* log ex.Message (contains exit code + helper error), retry or fall back */ }","preventionTips":["Enable GCM_TRACE=1 / GIT_TRACE2 to capture helper-side errors","Keep GCM updated for fixed helpers on your platform","Avoid killing the helper process mid-flow (watch for cleanup scripts)"],"tags":["process","helper","oauth","git-credential-manager"],"backgroundTag":"helper-process-failed","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"}