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

Unencrypted HTTP is not recommended for Azure Repos. Ensure…

Error message

Unencrypted HTTP is not recommended for Azure Repos. Ensure the repository remote URL is using HTTPS or see {Constants.HelpUrls.GcmUnsafeRemotes} about how to allow unsafe remotes.

What it means

ThrowIfUnsafeRemote guards against using unencrypted HTTP remotes with Azure Repos, since basic/token auth over HTTP would leak credentials. GCM refuses to authenticate against http:// Azure DevOps remotes unless the user explicitly opts in. The message points to a help page explaining how to allow unsafe remotes.

Solutions

  1. Change the remote URL to HTTPS: git remote set-url origin https://dev.azure.com/<org>/<project>/_git/<repo>
  2. If you genuinely must use HTTP (e.g. isolated test server), enable the unsafe-remotes option per the GcmUnsafeRemotes help URL
  3. Audit all remotes: git remote -v and convert any http:// Azure DevOps remotes

Example fix

// before
git remote set-url origin http://dev.azure.com/myorg/Proj/_git/repo
// after
git remote set-url origin https://dev.azure.com/myorg/Proj/_git/repo
Defensive patterns

Strategy: validation

Validate before calling

// C# / shell
// git config --get remote.origin.url | grep -E '^http://'   -> if match, rewrite to https
git remote set-url origin $(git remote get-url origin | sed 's|^http://|https://|')

Try / catch

try {
    await provider.GeneratePersonalAccessTokenAsync(input);
} catch (Trace2Exception ex) when (ex.Message.Contains("Unencrypted HTTP")) {
    Console.Error.WriteLine("Remote uses http://. Switch to https:// or enable unsafe remotes per GCM docs.");
}

Prevention

When it happens

Trigger: Calling GeneratePersonalAccessTokenAsync or GetEntraAccessTokenAsync for a GitRequest whose Protocol is 'http' (case-insensitive) while the azure.allowUnsafeRemotes (http.allowUnsafeRemotes-related) setting is not enabled.

Common situations: Cloning/pushing with a remote URL like http://dev.azure.com/... or http://<org>.visualstudio.com/...; mirrors or internal proxies configured with http://; docs or tooling generating http URLs by mistake.

Understand the failure class

Background: "Invalid URL" / "URL cannot be empty": fix the malformed or missing URL behind request-construction failures — this error's family across 50 libraries.

Related errors


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

Appendix: source

Thrown at src/Microsoft.AzureRepos/AzureReposHostProvider.cs:251

                // Clear the authority cache in case this was the reason for failure
                _authorityCache.EraseAuthority(orgName);
            }

            return Task.CompletedTask;
        }

        protected override void ReleaseManagedResources()
        {
            _azDevOps.Dispose();
            base.ReleaseManagedResources();
        }

        private void ThrowIfUnsafeRemote(GitRequest request)
        {
            if (!_context.Settings.AllowUnsafeRemotes &&
                StringComparer.OrdinalIgnoreCase.Equals(request.Protocol, "http"))
            {
                throw new Trace2Exception(_context.Trace2,
                    "Unencrypted HTTP is not recommended for Azure Repos. " +
                    "Ensure the repository remote URL is using HTTPS " +
                    $"or see {Constants.HelpUrls.GcmUnsafeRemotes} about how to allow unsafe remotes.");
            }
        }

        private async Task<ICredential> GeneratePersonalAccessTokenAsync(GitRequest request)
        {
            ThrowIfDisposed();
            ThrowIfUnsafeRemote(request);

            Uri remoteUserUri = request.GetRemoteUri(includeUser: true);
            Uri orgUri = UriHelpers.CreateOrganizationUri(remoteUserUri, out _);

            // Determine the Entra authentication authority for this organization
            _context.Trace.WriteLine("Determining Entra authentication authority...");
            string authAuthority = await _azDevOps.GetAuthorityAsync(orgUri);
            _context.Trace.WriteLine($"Authority is '{authAuthority}'.");

View on GitHub (pinned to e8ce762cd0)