HMCL-dev/HMCL · error · java.io.IOException
Unexpected file size
Error message
Unexpected file size: <downloaded>, expected: <contentLength>
What it means
FetchTask.download() counts bytes as they arrive and, when the server reported a non-negative content-length, verifies the downloaded byte count matches exactly. This IOException is thrown when the connection closed with fewer (or more) bytes than the advertised content-length, i.e. a truncated or corrupted transfer.
Solutions
- Simply retry the download — FetchTask's callers typically retry transient truncations
- Check network stability / switch mirror or proxy
- Verify server or CDN is not mangling content-length (e.g. compression middleware)
- If persistent, compare the file against its checksum to detect systematic truncation
Example fix
// before
fetchTask.run(); // may throw on truncation
// after
try {
fetchTask.run();
} catch (IOException e) {
if (e.getMessage().startsWith("Unexpected file size")) retryWithBackoff(fetchTask);
else throw e;
} Defensive patterns
Strategy: retry
Validate before calling
long expected = responseInfo.headers().firstValueAsLong("content-length").orElse(-1L);
if (expected >= 0) verifyDownloadedSize(file, expected); // pre/post check Try / catch
try {
fetchTask.run();
} catch (IOException e) {
if (e.getMessage().startsWith("Unexpected file size")) retryWithBackoff(fetchTask, 3);
else throw e;
} Prevention
- Use mirrors on stable network paths
- Verify final checksums after download as a second line of defense
- Monitor for specific mirrors with chronic truncation and drop them
When it happens
Trigger: Server closes the connection mid-transfer; proxy or CDN truncates the body; network drop during download; content-length header disagrees with the actual body size.
Common situations: Flaky Wi-Fi or mobile connections; overloaded mirrors (especially third-party Minecraft download mirrors); intermediaries that gzip or cut responses incorrectly.
Understand the failure class
Background: 'Something went wrong' / 'Request failed (500)' / 'HTTP error! status: 404' — what failed HTTP requests actually mean and how to find the real cause — this error's family across 28 libraries.
Related errors
- Failed to download theme background: HTTP
- Failed to download texture
- No download url is available
- Failed to download dependencies
- https://api.minecraftservices.com/entitlements/mcstore
AI-assisted analysis of HMCL-dev/HMCL@24702dc5a0 (2026-09-10).
Data as JSON: /api/errors/bf406fa8df048325.
Report an issue: GitHub.
Appendix: source
Thrown at HMCLCore/src/main/java/org/jackhuang/hmcl/task/FetchTask.java:272
if (resume != null)
resume.countUncompressed += len;
if (contentLength >= 0) {
// Update progress information per second
updateProgress(counter.downloaded, contentLength);
}
updateDownloadSpeed(counter.downloaded - lastDownloaded);
lastDownloaded = counter.downloaded;
}
if (isCancelled())
throw new InterruptedException();
updateDownloadSpeed(counter.downloaded - lastDownloaded);
if (contentLength >= 0 && counter.downloaded != contentLength)
throw new IOException("Unexpected file size: " + counter.downloaded + ", expected: " + contentLength);
success = true;
}
if (success) {
context.withResult(true);
}
}
private void downloadHttp(URI uri, boolean checkETag) throws DownloadException, InterruptedException {
if (checkETag) {
// Handle cache
try {
Path cache = repository.getCachedRemoteFile(uri, true);
useCachedResult(cache);
LOG.info("Using cached file for " + NetworkUtils.dropQuery(uri));
return;
} catch (IOException ignored) {View on GitHub (pinned to 24702dc5a0)