jib-core: ReproducibleLayerBuilder blob improperly closes the output stream
Author: scottjassoCreated May 18, 2026Updated Aug 11, 2026
Labelstype:bugpriority: p3
Environment:
- Jib version: jib-core: 0.28.1
- Build tool: gradle
- OS: Mac (irrelevant)
Description of the issue:
ReproducibleLayerBuilder builds a blob that first calls close on the underlying OutputStream (contrary to the javadoc), and then later calls flush, causing many OutputStream implementations to throw.
ReproducibleLayerBuilderusesTarStreamBuilderunder the hood. It returnsBlobs.from(tarStreamBuilder::writeAsTarArchiveTo, false), which creates aWriteableContentsBlob.TarStreamBuilder.writeAsTarArchiveTouses try-with-resources, which closes the underlying OutputStream when finished.WriteableContentsBlob.writeTousesDigests.computeDigest(writableContents, outputStream), which does this:
CountingDigestOutputStream digestOutStream = new CountingDigestOutputStream(outStream);
contents.writeTo(digestOutStream);
digestOutStream.flush();
return digestOutStream.computeDigest();Line 2 closes the digestOutputStream (because of writeAsTarArchiveTo), so then line 3 flushes after close.
Expected behavior:
Blob.writeTo should never call close on the OutputStream. You should be able to use any OutputStream.
TarStreamBuilder should not close the output stream passed to it.
Steps to reproduce:
ReproducibleLayerBuilder blob = new ReproducibleLayerBuilder(ImmutableList.of()).build();
// this causes ZstdOutputStream to throw IOException: StreamClosed
blob.writeTo(new ZstdOutputStream(new ByteArrayOutputStream()));Source: GoogleContainerTools/jib