jenkinsci/jenkins · error · IOException
Failed to unpack %s (%d bytes read of total %d)
Error message
Failed to unpack %s (%d bytes read of total %d)
What it means
Thrown during FilePath.install(...) when unpacking a downloaded zip/tar on the controller fails. The message reports bytes read vs the server's Content-Length so truncation is obvious. The IOException from unzipFrom/untarFrom is chained. This is the inner unpack failure; it is then re-wrapped by the outer 'Failed to install' handler.
Source
Thrown at core/src/main/java/hudson/FilePath.java:1063
timestamp.write(resultEtag, "UTF-8");
}
timestamp.touch(sourceTimestamp);
return true;
} catch (IOException x) {
Functions.printStackTrace(x, listener.error("Failed to download " + archive + " from agent; will retry from controller"));
}
}
// for HTTP downloads, enable automatic retry for added resilience
InputStream in = archive.getProtocol().startsWith("http") ? ProxyConfiguration.getInputStream(archive) : con.getInputStream();
CountingInputStream cis = new CountingInputStream(in);
try {
if (archive.toExternalForm().endsWith(".zip"))
unzipFrom(cis);
else
untarFrom(cis, TarCompression.GZIP);
} catch (IOException e) {
throw new IOException(String.format("Failed to unpack %s (%d bytes read of total %d)",
archive, cis.getByteCount(), con.getContentLength()), e);
}
if (resultEtag != null && !equalETags(etag, resultEtag)) {
/* Store the ETag value in the timestamp file for later use */
timestamp.write(resultEtag, "UTF-8");
}
timestamp.touch(sourceTimestamp);
return true;
} catch (IOException e) {
throw new IOException("Failed to install " + archive + " to " + remote, e);
}
}
/* Return true if etag1 equals etag2 as defined by the etag specification
https://httpwg.org/specs/rfc9110.html#field.etag
*/
private boolean equalETags(String etag1, String etag2) {
if (etag1 == null || etag2 == null) {View on GitHub (pinned to 2e228ff40b)
Solutions
- Compare bytes read vs total: if truncated, retry the download or fix the source URL.
- Verify the archive is valid: download separately and test with unzip/tar.
- Ensure the URL extension matches the format (.zip -> zip, else treated as gzipped tar).
- Check disk space and network stability; use a mirror if the source is unreliable.
Example fix
null
Defensive patterns
Strategy: retry
Validate before calling
URLConnection con = archive.openConnection(); int expected = con.getContentLength(); // after download, compare actual bytes to expected before unpacking
Type guard
null
Try / catch
try {
fp.install(archive, listener);
} catch (IOException e) {
if (e.getMessage().startsWith("Failed to unpack")) {
// truncated/corrupt download — retry from a stable source
} else throw e;
} Prevention
- Download from reliable mirrors/CDNs with retry logic.
- Verify byte count vs Content-Length before unpacking.
- Match the URL extension to the archive format (.zip vs tar.gz).
When it happens
Trigger: HTTP download truncated (bytes read < content length); corrupt or incomplete archive stream; gzip stream ended early; server reported a wrong Content-Length; connection dropped mid-transfer.
Common situations: Installing a tool/plugin/tool from a slow or proxy-mangled URL; server behind a CDN serving partial content; disk filled during unpack; mismatched archive type vs extension (.zip that is actually tar).
Related errors
- Failed to unpack %s (%d bytes read)
- There's no Jenkins running at {}
- expected to see initial zero byte; perhaps you are connectin
- There's no Jenkins running at {}, or is not serving the HTTP
- Failed to expand {}
AI-assisted analysis of jenkinsci/jenkins@2e228ff40b (2026-08-14).
Data as JSON: /api/errors/e2e35d5a18c72b21.
Report an issue: GitHub.