{"record":{"id":"7972f52ee7cfeffe","repo":"git-ecosystem/git-credential-manager","slug":"a-response-can-be-at-most-one-of-continue-cancel","errorCode":null,"errorMessage":"A response can be at most one of Continue, Cancel, or Yield.","messagePattern":"A response can be at most one of Continue, Cancel, or Yield\\.","errorType":"exception","errorClass":"ArgumentException","httpStatus":null,"severity":"error","filePath":"src/Core/GitResponse.cs","lineNumber":53,"sourceCode":"/// </para>\n/// <para>\n/// <see cref=\"AdditionalProperties\"/> is an escape hatch for arbitrary extra\n/// output keys that are not captured by the <see cref=\"State\"/> protocol capability.\n/// </para>\n/// </remarks>\npublic class GitResponse\n{\n    private readonly Dictionary<string, string> _state = new(StringComparer.Ordinal);\n    private ReadOnlyDictionary<string, string> _stateView;\n\n    private GitResponse(ICredential credential, bool isContinue, bool isCancelled, bool isYielded)\n    {\n        // At most one of Continue, Cancel, Yield may be set (Ok is \"none of them\").\n        if ((isContinue && isCancelled) ||\n            (isContinue && isYielded) ||\n            (isCancelled && isYielded))\n        {\n            throw new ArgumentException(\n                \"A response can be at most one of Continue, Cancel, or Yield.\");\n        }\n\n        bool hasCredential = credential is not null;\n\n        if ((isCancelled || isYielded) && hasCredential)\n        {\n            throw new ArgumentException(\n                \"A cancelled or yielded response cannot carry a credential.\",\n                nameof(credential));\n        }\n\n        if (!isCancelled && !isYielded && !hasCredential)\n        {\n            throw new ArgumentNullException(\n                nameof(credential),\n                \"A non-cancelled, non-yielded response must carry a credential. Use Cancel() or Yield() instead.\");\n        }","sourceCodeStart":35,"sourceCodeEnd":71,"githubUrl":"https://github.com/git-ecosystem/git-credential-manager/blob/e8ce762cd04b4100ae637b5fbf39ef9d0a96561e/src/Core/GitResponse.cs#L35-L71","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Return exactly one GitResponse kind per provider invocation: choose Continue, Cancel, Yield, or Ok.","Refactor flag-setting code into exclusive branches (if/else if) so only one flag can be set.","Add an early assertion or enum-based return kind instead of independent booleans in your provider."],"exampleFix":"// before\nreturn new GitResponse(credential, isContinue: true, isCancelled: shouldCancel);\n// after\nif (shouldCancel)\n    return GitResponse.Cancel();\nreturn GitResponse.Continue();","handlingStrategy":"validation","validationCode":"int kinds = (isContinue ? 1 : 0) + (isCancelled ? 1 : 0) + (isYielded ? 1 : 0);\nif (kinds > 1) throw new InvalidOperationException(\"Only one of Continue/Cancel/Yield may be set.\");","typeGuard":"bool IsExclusiveResponse(bool c, bool x, bool y) =>\n    !(c && x) && !(c && y) && !(x && y);","tryCatchPattern":"try\n{\n    var response = new GitResponse(credential, isContinue, isCancelled, isYielded);\n}\ncatch (ArgumentException ex) when (ex.Message.Contains(\"at most one of\"))\n{\n    // fix provider logic: return exactly one response kind\n}","preventionTips":["Model the response kind as a single enum instead of independent booleans.","Use exclusive if/else branches when deciding the response in providers.","Add unit tests asserting exactly one flag is set per constructed response.","Prefer static factories (Continue(), Cancel(), Yield()) over the raw constructor."],"tags":["git-protocol","response-validation","mutually-exclusive","argument-validation"],"backgroundTag":"mutually-exclusive-options","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"}