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

Extra query parameter

Error message

Extra query parameter '{kvp.Key}' would override required standard OAuth parameters.

What it means

In OAuth2Client.GetAuthorizationCodeAsync, any extra query parameters supplied by the caller are merged into the standard OAuth2 authorization request parameters. If an extra parameter's key collides with a required standard parameter (e.g. client_id, redirect_uri, response_type, scope, state, code_challenge), merging would silently corrupt the flow, so the library throws ArgumentException instead.

Solutions

  1. Remove keys from extraQueryParams that collide with standard OAuth2 authorization parameters.
  2. Only pass truly custom/extension parameters (e.g. 'prompt', 'domain_hint', tenant-specific extras) in extraQueryParams.
  3. Pre-filter the dictionary: drop any key that duplicates client_id, redirect_uri, response_type, scope, state, code_challenge, code_challenge_method before the call.
  4. Check config that feeds extraQueryParams for full copied URLs and strip their standard query strings.

Example fix

// before
await client.GetAuthorizationCodeAsync(endpoints, clientId, redirectUri, scopes, state, codeChallenge,
    new Dictionary<string,string> { ["state"] = "my-state" }); // throws
// after
var extra = new Dictionary<string,string> { ["domain_hint"] = "contoso.com" }; // no standard keys
await client.GetAuthorizationCodeAsync(endpoints, clientId, redirectUri, scopes, state, codeChallenge, extra);
Defensive patterns

Strategy: validation

Validate before calling

static readonly HashSet<string> StandardParams = new(StringComparer.Ordinal)
    { "client_id", "redirect_uri", "response_type", "scope", "state", "code_challenge", "code_challenge_method" };
bool conflicts = extra?.Keys.Any(StandardParams.Contains) == true;
if (conflicts) throw new ArgumentException("extraQueryParams may not override standard OAuth parameters.");

Try / catch

try
{
    result = await client.GetAuthorizationCodeAsync(endpoints, clientId, redirectUri, scopes, state, verifier, extra);
}
catch (ArgumentException ex) when (ex.ParamName == "extraQueryParams")
{
    // strip conflicting keys and retry once
    var safe = extra.Where(kvp => !StandardParams.Contains(kvp.Key)).ToDictionary(k => k.Key, v => v.Value);
    result = await client.GetAuthorizationCodeAsync(endpoints, clientId, redirectUri, scopes, state, verifier, safe);
}

Prevention

When it happens

Trigger: Calling GetAuthorizationCodeAsync with an extraQueryParams dictionary containing a key already present in the computed standard query parameters — for example passing 'redirect_uri', 'state', 'client_id', or 'scope' as an extra parameter.

Common situations: Configuration files that let users append arbitrary OAuth query parameters which accidentally include standard names; copying a full authorization URL's query string into extraQueryParams; SDK or wrapper code forwarding all options blindly.

Understand the failure class

Background: Conflicting config options: "cannot be used together" — configuration validation errors across open-source libraries — this error's family across 162 libraries.

Related errors


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

Appendix: source

Thrown at src/Core/Authentication/OAuth/OAuth2Client.cs:139

                [OAuth2Constants.AuthorizationEndpoint.PkceChallengeMethodParameter] =
                    OAuth2Constants.AuthorizationEndpoint.PkceChallengeMethodS256,
                [OAuth2Constants.AuthorizationEndpoint.PkceChallengeParameter] = codeChallenge
            };

            // Only send the parameter when requesting a non-default mode to keep the request unchanged otherwise.
            if (_responseMode != OAuth2ResponseMode.Default)
            {
                queryParams[OAuth2Constants.AuthorizationEndpoint.ResponseModeParameter] =
                    _responseMode.GetParameterValue();
            }

            if (extraQueryParams?.Count > 0)
            {
                foreach (var kvp in extraQueryParams)
                {
                    if (queryParams.ContainsKey(kvp.Key))
                    {
                        throw new ArgumentException(
                            $"Extra query parameter '{kvp.Key}' would override required standard OAuth parameters.",
                            nameof(extraQueryParams));
                    }

                    queryParams[kvp.Key] = kvp.Value;
                }
            }

            Uri redirectUri = null;
            if (_redirectUri != null)
            {
                redirectUri = browser.UpdateRedirectUri(_redirectUri);

                // We must use the .OriginalString property here over .ToString() because OAuth requires the redirect
                // URLs to be compared exactly, respecting missing/present trailing slashes, byte-for-byte.
                queryParams[OAuth2Constants.RedirectUriParameter] = redirectUri.OriginalString;
            }

View on GitHub (pinned to e8ce762cd0)