git-ecosystem/git-credential-manager · error · Trace2OAuth2Exception
Missing ' ' in response.
Error message
Missing '{OAuth2Constants.AuthorizationGrantResponse.AuthorizationCodeParameter}' in response. What it means
After validating state, GetAuthorizationCodeAsync requires the authorization 'code' parameter in the response. If the response parameters contain no authorization code the flow is terminated with this Trace2OAuth2Exception — the authorization server did not issue (or did not echo back) a code, so no token exchange is possible.
Solutions
- Check the response parameters for OAuth error fields (error, error_description) and surface them to the user before retrying.
- Ensure the complete redirect URL (query string intact) is captured and passed to GetAuthorizationCodeAsync.
- Prompt the user to retry the sign-in — a missing code often means the login/consent was not completed.
- Verify the redirect URI is registered correctly with the authorization server so it actually issues a code to your client.
Example fix
// before
var result = await client.GetAuthorizationCodeAsync(endpoints, clientId, redirectUri, scopes, state, verifier,
new Uri("https://client/callback?error=access_denied")); // no code
// after
if (responseParams.ContainsKey("error"))
throw new Exception($"Auth failed: {responseParams["error"]}");
var result = await client.GetAuthorizationCodeAsync(endpoints, clientId, redirectUri, scopes, state, verifier, successCallbackUrl); Defensive patterns
Strategy: try-catch
Validate before calling
var responseParams = ParseResponseParams(callbackUrl);
if (responseParams.TryGetValue("error", out var err))
throw new InvalidOperationException($"Authorization failed: {err}");
if (!responseParams.ContainsKey("code"))
throw new InvalidOperationException("Authorization response is missing 'code'."); Try / catch
try
{
result = await client.GetAuthorizationCodeAsync(endpoints, clientId, redirectUri, scopes, state, verifier, callbackUrl);
}
catch (Trace2OAuth2Exception ex) when (ex.Message.Contains("AuthorizationCodeParameter"))
{
// no auth code: user likely denied consent or login failed; surface error and allow retry
return AuthFailure.NoAuthorizationCode;
} Prevention
- Check for and display 'error'/'error_description' from the authorization response before treating it as a success response.
- Ensure the redirect URI is correctly registered so the server issues a code.
- Make sure the local listener captures the complete URL including query parameters.
- Design the UX to let users retry after a cancelled consent screen.
When it happens
Trigger: Calling GetAuthorizationCodeAsync with a response URL/parameters that lack the 'code' parameter — e.g. the user denied consent at the IdP and the redirect carried only an error, or the response URL was truncated/mangled before parsing.
Common situations: User cancelled the consent screen or login failed and the IdP redirected back with an error instead of a code; a local redirect listener dropped query parameters; proxy or URL-encoding issues stripped the code.
Related errors
- Extra query parameter
- Missing ' ' in response.
- OAuth2 response error (from device authorization endpoint…
- OAuth2 response error (from token endpoint response)
- Must specify at least one AuthenticationModes
AI-assisted analysis of git-ecosystem/git-credential-manager@e8ce762cd0 (2026-09-11).
Data as JSON: /api/errors/3825bd6d369104b0.
Report an issue: GitHub.
Appendix: source
Thrown at src/Core/Authentication/OAuth/OAuth2Client.cs:193
// Check for errors serious enough we should terminate the flow, such as if the state value returned does
// not match the one we passed. This indicates a badly implemented Authorization Server, or worse, some
// form of failed MITM or replay attack.
if (!responseParams.TryGetValue(OAuth2Constants.AuthorizationGrantResponse.StateParameter, out string replyState))
{
throw new Trace2OAuth2Exception(_trace2,
$"Missing '{OAuth2Constants.AuthorizationGrantResponse.StateParameter}' in response.");
}
if (!StringComparer.Ordinal.Equals(state, replyState))
{
throw new Trace2OAuth2Exception(_trace2,
$"Invalid '{OAuth2Constants.AuthorizationGrantResponse.StateParameter}' in response; does not match the request.");
}
// We expect to have the auth code in the response otherwise terminate the flow (we failed authentication for some reason)
if (!responseParams.TryGetValue(OAuth2Constants.AuthorizationGrantResponse.AuthorizationCodeParameter, out string authCode))
{
throw new Trace2OAuth2Exception(_trace2,
$"Missing '{OAuth2Constants.AuthorizationGrantResponse.AuthorizationCodeParameter}' in response.");
}
return new OAuth2AuthorizationCodeResult(authCode, redirectUri, codeVerifier);
}
public async Task<OAuth2DeviceCodeResult> GetDeviceCodeAsync(IEnumerable<string> scopes, CancellationToken ct)
{
var label = "get device code";
using IDisposable region = _trace2.CreateRegion(OAuth2Constants.Trace2Category, label);
if (_endpoints.DeviceAuthorizationEndpoint is null)
{
throw new Trace2InvalidOperationException(_trace2,
"No device authorization endpoint has been configured for this client.");
}
string scopesStr = string.Join(" ", scopes);
View on GitHub (pinned to e8ce762cd0)