git-ecosystem/git-credential-manager · error · Trace2Exception

Missing 'mode' in response

Error message

Missing 'mode' in response

What it means

Thrown by GetAuthenticationViaHelperAsync in GitLabAuthentication when the external Git credential helper command returns a result dictionary that does not contain a 'mode' key. The helper protocol requires every response to declare its authentication mode (pat, browser, or basic); without it GCM cannot decide how to proceed and fails fast with a Trace2Exception.

Solutions

  1. Update or fix the configured GitLab credential helper so it emits `mode=` (one of pat, browser, basic) in its output.
  2. Check the helper command configured via `credential.gitLabHelper` / GCM_GITLAB_HELPER and remove any broken override so GCM falls back to its built-in UI flow.
  3. Inspect helper stdout for stray log lines that break key=value parsing; redirect logging to stderr.

Example fix

// before (helper script output)
echo "pat=ghp_xxx"
// after
echo "mode=pat"
echo "pat=glpat_xxx"
Defensive patterns

Strategy: validation

Validate before calling

// Validate helper output before relying on it
class HelperResponseValidator {
  static bool HasMode(IDictionary<string, string> result) =>
    result != null && result.ContainsKey("mode") &&
    new[] { "pat", "browser", "basic" }.Contains(result["mode"].ToLowerInvariant());
}

Try / catch

try {
  var result = await auth.GetAuthenticationAsync(...);
} catch (Trace2Exception ex) when (ex.Message.Contains("Missing 'mode' in response")) {
  // fall back to built-in UI flow or prompt user to fix the helper
  logger.Warn("GitLab helper returned no mode; using built-in auth");
}

Prevention

When it happens

Trigger: Running `git-credential-manager gitlab` (GetAuthenticationAsync -> GetAuthenticationViaHelperAsync) where the configured helper executable (GitLabHelper.Command setting, e.g. a custom script) exits successfully but emits output without a `mode=` line.

Common situations: Custom or third-party GitLab credential helpers that print only a token; outdated helper scripts written for an older protocol; helper output parsed incorrectly due to extra logging polluting stdout.

Related errors


AI-assisted analysis of git-ecosystem/git-credential-manager@e8ce762cd0 (2026-09-11). Data as JSON: /api/errors/7c2609433a909c3f. Report an issue: GitHub.

Appendix: source

Thrown at src/GitLab/GitLabAuthentication.cs:219

        {
            var promptArgs = new StringBuilder(args);
            promptArgs.Append("prompt");
            if (!string.IsNullOrWhiteSpace(userName))
            {
                promptArgs.AppendFormat(" --username {0}", QuoteCmdArg(userName));
            }

            promptArgs.AppendFormat(" --url {0}", QuoteCmdArg(targetUri.ToString()));

            if ((modes & AuthenticationModes.Basic) != 0) promptArgs.Append(" --basic");
            if ((modes & AuthenticationModes.Browser) != 0) promptArgs.Append(" --browser");
            if ((modes & AuthenticationModes.Pat) != 0) promptArgs.Append(" --pat");

            IDictionary<string, string> resultDict = await InvokeHelperAsync(helperCommand, promptArgs.ToString());

            if (!resultDict.TryGetValue("mode", out string responseMode))
            {
                throw new Trace2Exception(Context.Trace2, "Missing 'mode' in response");
            }

            switch (responseMode.ToLowerInvariant())
            {
                case "pat":
                    if (!resultDict.TryGetValue("pat", out string pat))
                    {
                        throw new Trace2Exception(Context.Trace2, "Missing 'pat' in response");
                    }

                    if (!resultDict.TryGetValue("username", out string patUserName))
                    {
                        // Username is optional for PATs
                    }

                    return new AuthenticationPromptResult(
                        AuthenticationModes.Pat, new GitCredential(patUserName, pat));

View on GitHub (pinned to e8ce762cd0)