git-ecosystem/git-credential-manager · error · Trace2Exception
helper error ( )
Error message
helper error ({exitCode}): {errorMessage} What it means
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).
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).
Defensive patterns
Strategy: try-catch
Try / catch
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 */ } Prevention
- 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)
When it happens
Trigger: 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.).
Common situations: Helper crashed or user aborted in an unexpected way; helper failed OAuth token exchange; platform-specific helper bugs; corrupted helper output causing misparse.
Related errors
- Failed to start helper process
- No authentication mode selected!
- Failed to resolve username. HTTP
- Bitbucket DC OAuth Client ID must be defined
- Bitbucket DC OAuth Client Secret must be defined
AI-assisted analysis of git-ecosystem/git-credential-manager@e8ce762cd0 (2026-09-11).
Data as JSON: /api/errors/3ba6b2ca229738dc.
Report an issue: GitHub.
Appendix: source
Thrown at src/Core/Authentication/AuthenticationBase.cs:80
if (standardInput is not null)
{
await standardInput.BaseStream.CopyToAsync(process.StandardInput.BaseStream, ct);
process.StandardInput.Close();
}
IDictionary<string, string> resultDict = await process.StandardOutput.ReadDictionaryAsync(StringComparer.OrdinalIgnoreCase);
await Task.Run(() => process.WaitForExit(), ct);
int exitCode = process.ExitCode;
if (exitCode != 0)
{
if (!resultDict.TryGetValue("error", out string errorMessage))
{
errorMessage = "Unknown";
}
throw new Trace2Exception(Context.Trace2, $"helper error ({exitCode}): {errorMessage}");
}
return resultDict;
}
protected void ThrowIfUserInteractionDisabled()
{
if (!Context.Settings.IsInteractionAllowed)
{
string envName = Constants.EnvironmentVariables.GcmInteractive;
string cfgName = string.Format("{0}.{1}",
Constants.GitConfiguration.Credential.SectionName,
Constants.GitConfiguration.Credential.Interactive);
Context.Trace.WriteLine($"{envName} / {cfgName} is false/never; user interactivity has been disabled.");
throw new Trace2InvalidOperationException(Context.Trace2, "Cannot prompt because user interactivity has been disabled.");
}
}View on GitHub (pinned to e8ce762cd0)