LykosAI/StabilityMatrix · error · ApplicationException
Response is null
Error message
Response is null
What it means
ResumeDownloadToFileAsync resolves the download URL (including redirect targets), then loops with a small retry/backoff to obtain a response that reports a usable Content-Length for resuming a Range download. response stays null only when every one of the 4 retry attempts left remainingContentLength == 0 (i.e. the server never reported a content length, e.g. an empty 206/200 body), so this ApplicationException signals 'could not determine remaining content length after retries' — effectively a server not cooperating with resumable downloads.
Solutions
- Retry the download later or against a different mirror URL — the error usually means the host does not supply Content-Length for ranged responses.
- Verify the server supports Range requests (look for Accept-Ranges: bytes in the headers); if not, download the file from scratch instead of resuming.
- Check for proxies/VPNs stripping Content-Length and bypass them.
- Pass a named httpClientName with appropriate configuration (timeout, headers) for the specific host.
- If the partial file is already complete (existingFileSize == full size), skip ResumeDownloadToFileAsync entirely.
Example fix
// before
await downloadService.ResumeDownloadToFileAsync(url, path, existingSize);
// after
try
{
await downloadService.ResumeDownloadToFileAsync(url, path, existingSize);
}
catch (ApplicationException ex) when (ex.Message == "Response is null")
{
// Server never returned a usable content length after retries;
// fall back to a fresh (non-resume) download.
File.Delete(path);
await downloadService.DownloadToFileAsync(url, path);
} Defensive patterns
Strategy: fallback
Validate before calling
// Check the host supports ranged downloads before resuming
using var head = new HttpRequestMessage(HttpMethod.Head, downloadUrl);
using var resp = await httpClient.SendAsync(head);
bool resumable = resp.Headers.AcceptRanges?.Contains("bytes") == true
&& resp.Content.Headers.ContentLength > existingFileSize;
if (!resumable)
{
File.Delete(downloadPath); // start fresh instead of resuming
} Type guard
bool HasContentLength(HttpResponseMessage? r) =>
r?.Content?.Headers?.ContentLength is long len and > 0; Try / catch
try
{
await downloadService.ResumeDownloadToFileAsync(url, path, existingSize, progress, httpClientName, ct);
}
catch (ApplicationException ex) when (ex.Message == "Response is null")
{
logger.LogWarning(ex, "Resume failed: no content-length after retries; restarting download");
File.Delete(path);
await downloadService.DownloadToFileAsync(url, path, progress, httpClientName, ct);
} Prevention
- Confirm the host sends Accept-Ranges: bytes and Content-Length before resuming
- Avoid resuming through proxies/VPNs that strip response headers
- If the partial file is already fully sized, skip resume and verify the file
- Add a fallback to a full (non-resume) download wherever resume is used
When it happens
Trigger: Calling ResumeDownloadToFileAsync against a server whose ranged GET responses repeatedly lack a Content-Length header: the retry loop (4 attempts, 50ms decorrelated jitter backoff) exits without ever setting remainingContentLength > 0, so response is still the initial null when the guard at line 284 runs.
Common situations: Download hosts (CDNs, archives, mirrors) that don't honor Range requests or omit Content-Length on 206 responses; misconfigured proxies stripping headers; resuming a download that is actually already complete (remaining length 0) from a server that keeps returning indeterminate responses; transient server-side failures during all 4 quick retries.
Related errors
- Python download hash mismatch: expected , actual
- Client is not connected
- Source file does not exist
- Expected SageAttention file
- Hash validation for failed, expected but got
AI-assisted analysis of LykosAI/StabilityMatrix@af93d6ef57 (2026-09-12).
Data as JSON: /api/errors/f30d6170ff338a29.
Report an issue: GitHub.
Appendix: source
Thrown at StabilityMatrix.Core/Services/DownloadService.cs:286
file.Seek(0, SeekOrigin.Begin);
file.SetLength(0);
existingFileSize = 0;
}
originalContentLength =
response.Content.Headers.ContentRange?.Length.GetValueOrDefault()
?? (existingFileSize + remainingContentLength);
if (remainingContentLength > 0)
break;
logger.LogDebug("Retrying get-headers for content-length");
await Task.Delay(delay, cancellationToken).ConfigureAwait(false);
}
if (response == null)
{
throw new ApplicationException("Response is null");
}
var isIndeterminate = remainingContentLength == 0;
await using var stream = await response
.Content.ReadAsStreamAsync(cancellationToken)
.ConfigureAwait(false);
var totalBytesRead = 0L;
var stopwatch = Stopwatch.StartNew();
var buffer = new byte[BufferSize];
while (true)
{
cancellationToken.ThrowIfCancellationRequested();
var bytesRead = await stream.ReadAsync(buffer, cancellationToken).ConfigureAwait(false);
if (bytesRead == 0)
break;
await file.WriteAsync(buffer.AsMemory(0, bytesRead), cancellationToken).ConfigureAwait(false);View on GitHub (pinned to af93d6ef57)