subhra74/xdm · error · DownloadException
InvalidResponse
InvalidResponse
Error message
Invalid response: {e.Message} What it means
PieceGrabber.Download2 catches HttpException thrown by the HTTP response validation and, when the status code is a defined HttpStatusCode, rethrows it as a DownloadException with ErrorCode.InvalidResponse and message 'Invalid response: <original message>'. This converts raw HTTP failures during piece download into a typed download error.
Solutions
- Check the wrapped HttpException's StatusCode: 403/401 means re-fetch fresh URL/cookies; 416 means reset the resume offset and restart the piece
- Retry the piece download with fresh headers; signed CDN URLs frequently expire between segments
- For persistent 4xx/5xx, restart the whole download so PieceGrabber re-resolves the source URL
- Verify the server supports byte-range requests (Accept-Ranges); fall back to single-connection download if not
Example fix
// before
catch (HttpException e)
{
var status = e.StatusCode;
if (Enum.IsDefined(typeof(HttpStatusCode), status))
throw new DownloadException(ErrorCode.InvalidResponse, "Invalid response: " + e.Message, e);
}
// after
catch (HttpException e)
{
var status = e.StatusCode;
if (Enum.IsDefined(typeof(HttpStatusCode), status))
{
if ((int)status == 403 || (int)status == 401) RefreshSourceUrlAndCookies();
if ((int)status == 416) ResetPieceOffsets();
throw new DownloadException(ErrorCode.InvalidResponse,
$"Invalid response ({(int)status}): {e.Message}", e);
}
} Defensive patterns
Strategy: retry
Validate before calling
// Pre-check the piece URL and range support before Download2
var req = (HttpWebRequest)WebRequest.Create(pieceUrl);
req.Method = "HEAD";
using (var resp = (HttpWebResponse)await req.GetResponseAsync())
{
bool supportsRanges = resp.Headers[HttpResponseHeader.AcceptRanges] == "bytes";
if (!supportsRanges) FallBackToSingleConnectionDownload();
} Try / catch
try
{
grabber.Download2(...);
}
catch (DownloadException de) when (de.ErrorCode == ErrorCode.InvalidResponse)
{
var http = (HttpException)de.InnerException;
if ((int)http.StatusCode == 403 || (int)http.StatusCode == 401)
RefreshUrlAndCookiesThenRetry();
else if ((int)http.StatusCode == 416)
ResetResumeOffsetsThenRetry();
else
throw;
} Prevention
- Refresh signed/expiring URLs and cookies between piece downloads
- Verify the server supports byte ranges (Accept-Ranges: bytes) before multi-piece downloading
- Reset resume offsets after 416 Range Not Satisfiable responses
- Retry pieces on 5xx/429 with backoff before failing the whole download
When it happens
Trigger: Download2 requests a byte-range piece and the server responds with a non-success status (via EnsureSuccessStatusCode), whose message is wrapped into DownloadException(ErrorCode.InvalidResponse).
Common situations: Server returns 403/404 for range requests because the URL or signed token expired mid-download; 416 Range Not Satisfiable on bad resume offsets; 5xx from overloaded servers; CDN dropping support for the requested range.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
AI-assisted analysis of subhra74/xdm@1ca5a25aae (2026-09-13).
Data as JSON: /api/errors/4eaab3df07c92c76.
Report an issue: GitHub.
Appendix: source
Thrown at app/XDM/XDM.Core/Downloader/Progressive/PieceGrabber.cs:103
}
connectPhase = false;
this.Download(response);
}
OnComplete();
return;
}
catch (TextRedirectException e)
{
this.redirectUri = e.RedirectUri;
continue;
}
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();
View on GitHub (pinned to 1ca5a25aae)