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

A response can be at most one of Continue, Cancel, or Yield.

Error message

A response can be at most one of Continue, Cancel, or Yield.

What it means

The GitResponse constructor enforces that at most one of the Continue, Cancel, and Yield response kinds is set (with Ok meaning none of them). If more than one flag is simultaneously true, the constructor throws ArgumentException because such a response is semantically undefined for the Git credential protocol.

Solutions

  1. Return exactly one GitResponse kind per provider invocation: choose Continue, Cancel, Yield, or Ok.
  2. Refactor flag-setting code into exclusive branches (if/else if) so only one flag can be set.
  3. Add an early assertion or enum-based return kind instead of independent booleans in your provider.

Example fix

// before
return new GitResponse(credential, isContinue: true, isCancelled: shouldCancel);
// after
if (shouldCancel)
    return GitResponse.Cancel();
return GitResponse.Continue();
Defensive patterns

Strategy: validation

Validate before calling

int kinds = (isContinue ? 1 : 0) + (isCancelled ? 1 : 0) + (isYielded ? 1 : 0);
if (kinds > 1) throw new InvalidOperationException("Only one of Continue/Cancel/Yield may be set.");

Type guard

bool IsExclusiveResponse(bool c, bool x, bool y) =>
    !(c && x) && !(c && y) && !(x && y);

Try / catch

try
{
    var response = new GitResponse(credential, isContinue, isCancelled, isYielded);
}
catch (ArgumentException ex) when (ex.Message.Contains("at most one of"))
{
    // fix provider logic: return exactly one response kind
}

Prevention

When it happens

Trigger: Constructing GitResponse with mutually conflicting flags — e.g. new GitResponse(credential, isContinue: true, isCancelled: true) or combining yield with continue — typically from buggy provider code that sets status flags independently instead of returning one definitive response kind.

Common situations: Custom credential helper/provider implementations that fall through multiple branches and set both continue and cancel; refactors that changed return types to flags without exclusive-or validation; porting logic from providers that allowed multiple actions.

Related errors


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

Appendix: source

Thrown at src/Core/GitResponse.cs:53

/// </para>
/// <para>
/// <see cref="AdditionalProperties"/> is an escape hatch for arbitrary extra
/// output keys that are not captured by the <see cref="State"/> protocol capability.
/// </para>
/// </remarks>
public class GitResponse
{
    private readonly Dictionary<string, string> _state = new(StringComparer.Ordinal);
    private ReadOnlyDictionary<string, string> _stateView;

    private GitResponse(ICredential credential, bool isContinue, bool isCancelled, bool isYielded)
    {
        // At most one of Continue, Cancel, Yield may be set (Ok is "none of them").
        if ((isContinue && isCancelled) ||
            (isContinue && isYielded) ||
            (isCancelled && isYielded))
        {
            throw new ArgumentException(
                "A response can be at most one of Continue, Cancel, or Yield.");
        }

        bool hasCredential = credential is not null;

        if ((isCancelled || isYielded) && hasCredential)
        {
            throw new ArgumentException(
                "A cancelled or yielded response cannot carry a credential.",
                nameof(credential));
        }

        if (!isCancelled && !isYielded && !hasCredential)
        {
            throw new ArgumentNullException(
                nameof(credential),
                "A non-cancelled, non-yielded response must carry a credential. Use Cancel() or Yield() instead.");
        }

View on GitHub (pinned to e8ce762cd0)