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

Provided URI ' ' is not a valid Azure DevOps hostname

Error message

Provided URI '{organizationUri}' is not a valid Azure DevOps hostname

What it means

CreatePersonalAccessTokenAsync validates that the organization URI host is a recognized Azure DevOps host (dev.azure.com or *.visualstudio.com per UriHelpers.IsAzureDevOpsHost) before calling the API. A non-DevOps URL raises ArgumentException naming the offending URI.

Solutions

  1. Pass the hosted Azure DevOps organization URL, e.g. https://dev.azure.com/your-org/.
  2. For on-premises Azure DevOps Server, do not use this hosted-host validation path - configure the provider for Azure DevOps Server explicitly.
  3. Verify the host with UriHelpers.IsAzureDevOpsHost logic before calling; fix typos in the hostname.

Example fix

// before
var uri = new Uri("https://mycompany.visualstudio.com.default/MyProj");
// after
var uri = new Uri("https://dev.azure.com/myorganization");
Defensive patterns

Strategy: validation

Validate before calling

// Validate the org URI host before calling CreatePersonalAccessTokenAsync
var uri = new Uri(organizationUri);
bool isAdoHost = uri.Host == "dev.azure.com" || uri.Host.EndsWith(".visualstudio.com");
if (!isAdoHost) throw new ArgumentException($"{organizationUri} is not a hosted Azure DevOps organization URL");

Try / catch

try {
  var pat = await restApi.CreatePersonalAccessTokenAsync(orgUri, accessToken);
} catch (ArgumentException ex) when (ex.Message.Contains("not a valid Azure DevOps hostname")) {
  // normalize to https://dev.azure.com/{org} and retry
}

Prevention

When it happens

Trigger: Calling AzureDevOpsRestApi.CreatePersonalAccessTokenAsync with a URI whose host is not an Azure DevOps hostname - e.g. an on-premises Azure DevOps Server URL, a GitHub/GitLab URL, or a mistyped host.

Common situations: Using GCM's Azure DevOps PAT creation against Azure DevOps Server (on-prem) which has a custom hostname; passing a full repository URL instead of the organization URL; DNS typos.

Understand the failure class

Background: "Invalid URL" errors: why new URL(), URI.parse, and reqwest::Url reject your string — missing scheme, whitespace, and bad path format — this error's family across 39 libraries.

Related errors


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

Appendix: source

Thrown at src/Microsoft.AzureRepos/AzureDevOpsRestApi.cs:113

                    AzureDevOpsConstants.EnvironmentVariables.DevAadAuthorityBaseUri,
                    Constants.GitConfiguration.Credential.SectionName, AzureDevOpsConstants.GitConfiguration.Credential.DevAadAuthorityBaseUri,
                    out string redirectUriStr) &&
                Uri.TryCreate(redirectUriStr, UriKind.Absolute, out Uri authorityBase))
            {
                return authorityBase;
            }

            return new Uri(AzureDevOpsConstants.AadAuthorityBaseUrl);
        }

        public async Task<string> CreatePersonalAccessTokenAsync(Uri organizationUri, string accessToken, IEnumerable<string> scopes)
        {
            const string sessionTokenUrl = "_apis/token/sessiontokens?api-version=1.0&tokentype=compact";

            EnsureArgument.AbsoluteUri(organizationUri, nameof(organizationUri));
            if (!UriHelpers.IsAzureDevOpsHost(organizationUri.Host))
            {
                throw new ArgumentException($"Provided URI '{organizationUri}' is not a valid Azure DevOps hostname", nameof(organizationUri));
            }
            EnsureArgument.NotNull(accessToken, nameof(accessToken));

            _context.Trace.WriteLine("Getting Azure DevOps Identity Service endpoint...");
            Uri identityServiceUri = await GetIdentityServiceUriAsync(organizationUri, accessToken);
            _context.Trace.WriteLine($"Identity Service endpoint is '{identityServiceUri}'.");

            Uri requestUri = new Uri(identityServiceUri, sessionTokenUrl);

            _context.Trace.WriteLine($"HTTP: POST {requestUri}");
            using (StringContent content = CreateAccessTokenRequestJson(organizationUri, scopes))
            using (HttpRequestMessage request = CreateRequestMessage(HttpMethod.Post, requestUri, content, accessToken))
            using (HttpResponseMessage response = await HttpClient.SendAsync(request))
            {
                _context.Trace.WriteLine($"HTTP: Response {(int)response.StatusCode} [{response.StatusCode}]");

                string responseText = await response.Content.ReadAsStringAsync();

View on GitHub (pinned to e8ce762cd0)