duplicati/duplicati · error · Exception

Download URL is missing from authorization response

Error message

Download URL is missing from authorization response

What it means

Thrown in B2AuthHelper.GetConfigAsync (B2AuthHelper.cs:140) when the auth response parsed successfully but the downloadUrl field is empty or whitespace. ApiAuthResponse.DownloadUrl maps to the downloadUrl JSON property and is nullable string?. The downloadUrl is used for file download operations (GetAsync). Retried up to 5 times before surfacing.

Source

Thrown at Duplicati/Library/Backend/Backblaze/B2AuthHelper.cs:140

                {
                    response = await _httpClient.SendAsync(request, ct).ConfigureAwait(false);
                    response.EnsureSuccessStatusCode();

                    return await ReadJsonResponseAsync<ApiAuthResponse>(response, ct).ConfigureAwait(false)
                        ?? throw new Exception("Failed to parse authorization response");
                }).ConfigureAwait(false);

                if (string.IsNullOrWhiteSpace(authResponse.AccountID))
                    throw new Exception("Account ID is missing from authorization response");

                if (string.IsNullOrWhiteSpace(authResponse.APIUrl))
                    throw new Exception("API URL is missing from authorization response");

                if (string.IsNullOrWhiteSpace(authResponse.AuthorizationToken))
                    throw new Exception("Authorization token is missing from authorization response");

                if (string.IsNullOrWhiteSpace(authResponse.DownloadUrl))
                    throw new Exception("Download URL is missing from authorization response");

                authResponse.APIUrl = DropTrailingSlashes(authResponse.APIUrl);
                authResponse.DownloadUrl = DropTrailingSlashes(authResponse.DownloadUrl);
                _configExpires = DateTime.UtcNow + TimeSpan.FromMinutes(CACHE_EXPIRATION_MINUTES);

                return _CachedAuthResponse = new AuthResponse(authResponse.AccountID, authResponse.APIUrl, authResponse.AuthorizationToken, authResponse.DownloadUrl);
            }
            catch (Exception ex)
            {
                var clientError = false;

                try
                {
                    // Only retry once on client errors
                    if (ex is HttpRequestException { StatusCode: not null } exception)
                    {
                        var sc = (int)exception.StatusCode;
                        clientError = sc is >= 400 and <= 499;

View on GitHub (pinned to 3f348be3e3)

Solutions

  1. Verify direct connectivity to api.backblazeb2.com without TLS interception
  2. Regenerate the application key and retry
  3. Retry after a few minutes to rule out transient B2 issues
Defensive patterns

Strategy: try-catch

Try / catch

try { var config = await b2AuthHelper.GetConfigAsync(cancelToken); }
catch (Exception ex) when (ex.Message == "Download URL is missing from authorization response")
{
    logger.LogError(ex, "B2 auth response missing downloadUrl after retries");
    throw;
}

Prevention

When it happens

Trigger: The deserialized ApiAuthResponse lacks downloadUrl. After 5 retries, the bare Exception propagates. This field is needed for constructing download URLs in GetAsync.

Common situations: Proxy stripping downloadUrl from the auth response; B2 API schema change; response truncation by intermediary.

Related errors


AI-assisted analysis of duplicati/duplicati@3f348be3e3 (2026-08-13). Data as JSON: /api/errors/7e14989f4f958073. Report an issue: GitHub.