{"record":{"id":"bb3d5add8548001a","repo":"git-ecosystem/git-credential-manager","slug":"missing-pat-in-response","errorCode":null,"errorMessage":"Missing 'pat' in response","messagePattern":"Missing 'pat' in response","errorType":"exception","errorClass":"Trace2Exception","httpStatus":null,"severity":"error","filePath":"src/GitHub/GitHubAuthentication.cs","lineNumber":317,"sourceCode":"            }\n\n            if (!GitHubHostProvider.IsGitHubDotCom(targetUri))\n                promptArgs.AppendFormat(\" --enterprise-url {0}\", QuoteCmdArg(targetUri.ToString()));\n            if (!string.IsNullOrWhiteSpace(userName)) promptArgs.AppendFormat(\" --username {0}\", QuoteCmdArg(userName));\n\n            IDictionary<string, string> resultDict = await InvokeHelperAsync(command, promptArgs.ToString(), null);\n\n            if (!resultDict.TryGetValue(\"mode\", out string responseMode))\n            {\n                throw new Trace2Exception(Context.Trace2, \"Missing 'mode' in response\");\n            }\n\n            switch (responseMode.ToLowerInvariant())\n            {\n                case \"pat\":\n                    if (!resultDict.TryGetValue(\"pat\", out string pat))\n                    {\n                        throw new Trace2Exception(Context.Trace2, \"Missing 'pat' in response\");\n                    }\n\n                    return new AuthenticationPromptResult(\n                        AuthenticationModes.Pat, new GitCredential(userName, pat));\n\n                case \"browser\":\n                    return new AuthenticationPromptResult(AuthenticationModes.Browser);\n\n                case \"device\":\n                    return new AuthenticationPromptResult(AuthenticationModes.Device);\n\n                case \"basic\":\n                    if (!resultDict.TryGetValue(\"username\", out userName))\n                    {\n                        throw new Trace2Exception(Context.Trace2, \"Missing 'username' in response\");\n                    }\n\n                    if (!resultDict.TryGetValue(\"password\", out string password))","sourceCodeStart":299,"sourceCodeEnd":335,"githubUrl":"https://github.com/git-ecosystem/git-credential-manager/blob/e8ce762cd04b4100ae637b5fbf39ef9d0a96561e/src/GitHub/GitHubAuthentication.cs#L299-L335","documentation":"When the helper reports response mode 'pat', the response dictionary must also contain a 'pat' key with the personal access token. If mode is 'pat' but no token value accompanies it, the contract between helper and core is violated and this Trace2Exception is thrown — a credential cannot be constructed without the token.","triggerScenarios":"Helper returns mode=pat but the 'pat' entry is absent: the helper's PAT collection step was interrupted, an incompatible/buggy helper version emitted mode without the token, or the dictionary was truncated during parsing.","commonSituations":"User cancels midway through the PAT dialog but helper still emits mode=pat; version skew between GCM core and UI helper after a partial upgrade; custom/third-party helper implementations that forget the pat key.","solutions":["Update Git Credential Manager to a matching, current version so helper and core agree on the response contract","Capture GCM_TRACE output and run the helper manually to inspect the raw key/value response","Retry the authentication flow and complete the PAT entry fully","If writing a custom helper, always emit both mode=pat and the pat key together"],"exampleFix":"// before\nif (!resultDict.TryGetValue(\"pat\", out string pat)) throw new Trace2Exception(Context.Trace2, \"Missing 'pat' in response\");\n// after (helper side: ensure both keys emitted)\nif (!string.IsNullOrEmpty(collectedPat))\n{\n    output[\"mode\"] = \"pat\";\n    output[\"pat\"] = collectedPat;\n}","handlingStrategy":"validation","validationCode":"// Caller-side sanity check pattern: confirm helper contract before trusting a custom helper\n// (run helper manually and parse output)\nvar output = RunHelper(\"github get-authenticator\");\nbool valid = output.ContainsKey(\"mode\") &&\n             (output[\"mode\"] != \"pat\" || output.ContainsKey(\"pat\"));\nif (!valid) throw new InvalidOperationException(\"Helper response incomplete for pat mode.\");","typeGuard":null,"tryCatchPattern":"try\n{\n    var result = await auth.GetAuthenticationAsync(uri, userName);\n}\ncatch (Trace2Exception ex) when (ex.Message == \"Missing 'pat' in response\")\n{\n    // retry the prompt once, then surface a helper-contract error\n    trace.WriteLine(\"Helper emitted mode=pat without token; retrying.\");\n    throw;\n}","preventionTips":["Custom helpers must emit mode and pat keys atomically","Avoid partial upgrades: update GCM core and helper together","Capture GCM_TRACE logs when the PAT flow misbehaves","Test custom helper output against the documented key contract"],"tags":["github","authentication","pat","helper-contract"],"backgroundTag":"response-missing-required-field","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"}