git-ecosystem/git-credential-manager · error · ArgumentException
Must specify at least one
Error message
Must specify at least one {nameof(AuthenticationModes)} What it means
GitLabAuthentication.GetAuthenticationAsync reduces the requested AuthenticationModes (removing unavailable modes like Browser when no desktop session exists) and if nothing remains (modes == AuthenticationModes.None) throws ArgumentException because there is no viable authentication method for the GitLab host.
Solutions
- Set credential.gitLabAuthModes (or GCM_GITLAB_AUTHMODES env var) to include an available mode such as Pat (comma-separated list of Browser, Pat, etc.).
- Do not pass AuthenticationModes.None when calling the API programmatically.
- Run in an environment with a desktop session if you rely on Browser mode.
- Provide a PAT so interactive modes can be bypassed entirely (GCM_INTERACTIVE=Never plus stored credential).
Example fix
// before git config --global credential.gitLabAuthModes browser // headless: mode stripped -> None // after git config --global credential.gitLabAuthModes pat,browser
Defensive patterns
Strategy: validation
Validate before calling
var raw = Environment.GetEnvironmentVariable("GCM_GITLAB_AUTHMODES")
?? config["credential.gitLabAuthModes"];
var modes = ParseModes(raw); // parse comma-separated Browser,Pat,...
if (modes == AuthenticationModes.None)
{
modes = AuthenticationModes.Pat; // ensure at least one viable mode
}
if (!hasDesktopSession) modes &= ~AuthenticationModes.Browser;
if (modes == AuthenticationModes.None) throw new InvalidOperationException("No viable GitLab auth mode configured"); Try / catch
try
{
var result = await gitLabAuth.GetAuthenticationAsync(targetUri, userName, modes);
}
catch (ArgumentException ex) when (ex.ParamName == "modes")
{
// retry with a default mode set including Pat
} Prevention
- Always include Pat in credential.gitLabAuthModes for headless environments
- Never pass AuthenticationModes.None programmatically
- Verify Browser mode availability (desktop session) before relying on it
- Store a GitLab PAT so interactive modes are optional
When it happens
Trigger: Calling GetAuthenticationAsync with AuthenticationModes.None, or with modes that all get stripped (e.g. only Browser requested in a headless session, or PAT disabled by config) leaving None.
Common situations: Configuring credential.gitLabAuthModes to a single mode that is unavailable in the environment (Browser on a server without a desktop session); passing None programmatically; GCM detecting no desktop session so interactive modes are removed.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
- Authentication and authorization failures — expired tokens, bad credentials, and missing scopes.
Related errors
- Must specify at least one AuthenticationModes
- Unexpected interaction mode.
- Public client configuration is required for user…
- No authentication mode selected!
- At least one must be supplied
AI-assisted analysis of git-ecosystem/git-credential-manager@e8ce762cd0 (2026-09-11).
Data as JSON: /api/errors/e64f7fdc3371c4e8.
Report an issue: GitHub.
Appendix: source
Thrown at src/GitLab/GitLabAuthentication.cs:72
}
public class GitLabAuthentication : AuthenticationBase, IGitLabAuthentication
{
public GitLabAuthentication(ICommandContext context)
: base(context) { }
public async Task<AuthenticationPromptResult> GetAuthenticationAsync(Uri targetUri, string userName, AuthenticationModes modes)
{
// If we cannot start a browser then don't offer the option
if (!Context.SessionManager.IsWebBrowserAvailable)
{
modes = modes & ~AuthenticationModes.Browser;
}
// We need at least one mode!
if (modes == AuthenticationModes.None)
{
throw new ArgumentException(@$"Must specify at least one {nameof(AuthenticationModes)}", nameof(modes));
}
ThrowIfUserInteractionDisabled();
if (Context.Settings.IsGuiPromptsEnabled && Context.SessionManager.IsDesktopSession)
{
if (TryFindHelperCommand(out string helperCommand, out string args))
{
return await GetAuthenticationViaHelperAsync(targetUri, userName, modes, helperCommand, args);
}
return await GetAuthenticationViaUiAsync(targetUri, userName, modes);
}
return await GetAuthenticationViaTtyAsync(targetUri, userName, modes);
}
private async Task<AuthenticationPromptResult> GetAuthenticationViaUiAsync(View on GitHub (pinned to e8ce762cd0)