dotnet/machinelearning · error · NotSupportedException

The function ResourceManagerUtils.EnsureResourceAsync only s

Error message

The function ResourceManagerUtils.EnsureResourceAsync only supports downloading from URLs of the host "aka.ms"

What it means

ResourceManagerUtils.EnsureResourceAsync downloads ML.NET resources (e.g. image-model pretrained models) from a known base URL, then only permits downloads whose resolved absolute host is exactly "aka.ms". Any other host throws NotSupportedException because Microsoft restricts this code path to its own trusted short-link domain, both for security (avoiding arbitrary downloads) and licensing. This is an intentional allowlist, not a bug.

Source

Thrown at src/Microsoft.ML.Core/Utilities/ResourceManagerUtils.cs:120

        /// <param name="fileName">The name of the file to save.</param>
        /// <param name="dir">The directory where the file should be saved to. The file will be saved in a directory with the specified name inside
        /// a folder called "mlnet-resources" in the <see cref="Environment.SpecialFolder.ApplicationData"/> directory.</param>
        /// <param name="timeout">An integer indicating the number of milliseconds to wait before timing out while downloading a resource.</param>
        /// <returns>The download results, containing the file path where the resources was (or should have been) downloaded to, and an error message
        /// (or null if there was no error).</returns>
        public async Task<ResourceDownloadResults> EnsureResourceAsync(IHostEnvironment env, IChannel ch, string relativeUrl, string fileName, string dir, int timeout)
        {
            var filePath = GetFilePath(ch, fileName, dir, out var error);
            if (File.Exists(filePath) || !string.IsNullOrEmpty(error))
                return new ResourceDownloadResults(filePath, error);

            if (!Uri.TryCreate(Path.Combine(MlNetResourcesUrl, relativeUrl), UriKind.Absolute, out var absoluteUrl))
            {
                return new ResourceDownloadResults(filePath,
                    $"Could not create a valid URI from the base URI '{MlNetResourcesUrl}' and the relative URI '{relativeUrl}'");
            }
            if (absoluteUrl.Host != "aka.ms")
                throw new NotSupportedException("The function ResourceManagerUtils.EnsureResourceAsync only supports downloading from URLs of the host \"aka.ms\"");
            return new ResourceDownloadResults(filePath,
                await DownloadFromUrlWithRetryAsync(env, ch, absoluteUrl.AbsoluteUri, fileName, timeout, filePath), absoluteUrl.AbsoluteUri);
        }

        private async Task<string> DownloadFromUrlWithRetryAsync(IHostEnvironment env, IChannel ch, string url, string fileName,
            int timeout, string filePath, int retryTimes = 5)
        {
            var downloadResult = "";

            for (int i = 0; i < retryTimes; ++i)
            {
                try
                {
                    var thisDownloadResult = await DownloadFromUrlAsync(env, ch, url, fileName, timeout, filePath);

                    if (string.IsNullOrEmpty(thisDownloadResult))
                        return thisDownloadResult;
                    else

View on GitHub (pinned to 7b76e69cf9)

Solutions

  1. Use only URLs whose final absolute host is "aka.ms"; revert any customization of the resources base URL to the default Microsoft endpoint.
  2. If you need resources from another host, download the file yourself (e.g. with HttpClient) and register/place it in the expected local cache path instead of using EnsureResourceAsync.
  3. Check the composed URL: combine MlNetResourcesUrl with relativeUrl using Uri.TryCreate and inspect .Host before calling, so you know what the method will see.

Example fix

// before
var results = await ResourceManagerUtils.Instance.EnsureResourceAsync(env, ch,
    "https://example.com/models/model.res", "model.res", timeout);
// after
if (new Uri(modelUrl).Host == "aka.ms")
{
    var results = await ResourceManagerUtils.Instance.EnsureResourceAsync(env, ch,
        modelUrl, "model.res", timeout);
}
else
{
    // download manually and place the file in the expected cache location
    await DownloadToCacheAsync(modelUrl, cachePath);
}
Defensive patterns

Strategy: validation

Validate before calling

if (Uri.TryCreate(Path.Combine(MlNetResourcesUrl, relativeUrl), UriKind.Absolute, out var abs)
    && abs.Host == "aka.ms")
{
    await ResourceManagerUtils.Instance.EnsureResourceAsync(env, ch, relativeUrl, fileName, timeout);
}

Type guard

static bool IsAllowedResourceUrl(Uri url) => url?.Host == "aka.ms";

Try / catch

try
{
    await ResourceManagerUtils.Instance.EnsureResourceAsync(env, ch, relativeUrl, fileName, timeout);
}
catch (NotSupportedException ex)
{
    // non-aka.ms host: fall back to manual download or surface config error
}

Prevention

When it happens

Trigger: Calling ResourceManagerUtils.EnsureResourceAsync with a relativeUrl that resolves against MlNetResourcesUrl to a non-aka.ms host (e.g. after MlNetResourcesUrl was redirected, overridden for testing, or the relative path escaped the aka.ms domain via '../' segments).

Common situations: Enterprise environments redirecting aka.ms through a proxy/mirror domain; developers pointing the resource manager at a custom mirror to work offline; test setups substituting a local base URL; DNS/CDN changes causing aka.ms short links to resolve under a different host string.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


AI-assisted analysis of dotnet/machinelearning@7b76e69cf9 (2026-09-11). Data as JSON: /api/errors/c7231bf9555e6470. Report an issue: GitHub.