subhra74/xdm · error · DownloadException

MaxRetryFailed

MaxRetryFailed

Error message

Max retry exceeded

What it means

PieceGrabber retries a failing download loop up to Config.Instance.MaxRetry times. Each caught failure increments timesRetried and, when the counter exceeds MaxRetry, the grabber throws DownloadException with ErrorCode.MaxRetryFailed. It means the piece repeatedly failed to connect or transfer and the library has given up retrying.

Solutions

  1. Increase Config.Instance.MaxRetry to allow more attempts on unstable networks.
  2. Increase Config.Instance.RetryDelay to give the server/network time to recover between attempts.
  3. Check network stability (proxy, VPN, firewall) and retry the download manually.
  4. Wrap download orchestration to catch MaxRetryFailed and restart the download from persisted pieces.

Example fix

// before
var cfg = Config.Instance; // MaxRetry = 3
// after
var cfg = Config.Instance;
cfg.MaxRetry = 10;      // tolerate unstable links
cfg.RetryDelay = 5;     // seconds between attempts
Defensive patterns

Strategy: retry

Validate before calling

// before starting
if (Config.Instance.MaxRetry < 5) Config.Instance.MaxRetry = 5;
if (!NetworkInterface.GetIsNetworkAvailable()) throw new InvalidOperationException("No network");

Try / catch

try { downloader.Download(); }
catch (DownloadException e) when (e.ErrorCode == ErrorCode.MaxRetryFailed) {
    Log.Warn("Giving up after max retries");
    ScheduleRetryWithBackoff();
}

Prevention

When it happens

Trigger: The inner download block throws a retryable exception (network drop, connection reset, timeout) more than MaxRetry consecutive times inside PieceGrabber's loop; cancellation and non-retriable exceptions (AssembleFailedException, NonRetriableException, OperationCanceledException) are rethrown instead and never reach this path.

Common situations: Flaky or throttled network connections, servers that keep rejecting range requests, MaxRetry configured too low (default small) on unreliable links, firewalls/proxies intermittently killing persistent connections.

Understand the failure class

Background: Request timed out: what client-side request timeouts mean across libraries (Request timed out, TIMED_OUT, APITimeoutError) — this error's family across 39 libraries.

Related errors


AI-assisted analysis of subhra74/xdm@1ca5a25aae (2026-09-13). Data as JSON: /api/errors/b9256fde332cb813. Report an issue: GitHub.

Appendix: source

Thrown at app/XDM/XDM.Core/Downloader/Progressive/PieceGrabber.cs:116

                    catch (HttpException e)
                    {
                        var status = e.StatusCode;
                        if (Enum.IsDefined(typeof(HttpStatusCode), status))
                        {
                            throw new DownloadException(ErrorCode.InvalidResponse,
                                "Invalid response: " + e.Message, e);
                        }
                    }
                    catch (Exception e)
                    {
                        if (e is KeyNotFoundException || this.CancellationToken.IsCancellationRequested) return;
                        if (e is AssembleFailedException || e is NonRetriableException || e is OperationCanceledException) throw;
                        Log.Debug(e, "Error in PieceGrabber inner block - swallowing error - isCancelled: " + this.cancellationTokenSource.IsCancellationRequested);
                    }
                    timesRetried++;
                    if (timesRetried > Config.Instance.MaxRetry)
                    {
                        throw new DownloadException(ErrorCode.MaxRetryFailed, "Max retry exceeded");
                    }
                    if (connectPhase)
                    {
                        sleep(Config.Instance.RetryDelay * 1000);
                        CancellationToken.ThrowIfCancellationRequested();
                        //await Task.Delay(Config.Instance.RetryDelay * 1000,
                        //    this.CancellationToken).ConfigureAwait(false);
                    }
                }
            }
            catch (Exception e)
            {
                if (e is KeyNotFoundException || this.CancellationToken.IsCancellationRequested)
                {
                    return;
                }
                Log.Debug(e, "Error in PieceGrabber outer block");
                if (this.pieceId != null)

View on GitHub (pinned to 1ca5a25aae)