GoogleContainerTools/jib · error · IllegalStateException
Cannot rewrite Blob backed by an InputStream
Error message
Cannot rewrite Blob backed by an InputStream
What it means
An InputStreamBlob streams its content once (computing its digest while writing). Because the underlying InputStream is consumed and closed on first writeTo, the Blob cannot be written a second time; a repeated writeTo throws IllegalStateException 'Cannot rewrite Blob backed by an InputStream'.
Source
Thrown at jib-core/src/main/java/com/google/cloud/tools/jib/blob/InputStreamBlob.java:40
import java.io.OutputStream;
/** A {@link Blob} that holds an {@link InputStream}. */
class InputStreamBlob implements Blob {
private final InputStream inputStream;
/** Indicates if the {@link Blob} has already been written or not. */
private boolean isWritten = false;
InputStreamBlob(InputStream inputStream) {
this.inputStream = inputStream;
}
@Override
public BlobDescriptor writeTo(OutputStream outStream) throws IOException {
// Cannot rewrite.
if (isWritten) {
throw new IllegalStateException("Cannot rewrite Blob backed by an InputStream");
}
try (InputStream inStream = this.inputStream) {
return Digests.computeDigest(inStream, outStream);
} finally {
isWritten = true;
}
}
@Override
public boolean isRetryable() {
return false;
}
}
View on GitHub (pinned to fb949e2676)
Solutions
- Create a fresh InputStreamBlob (new InputStream) for each write attempt.
- Buffer the content first, e.g. Blobs.from(byte[]) or write the stream to a temp file and use a file-backed Blob, which is replayable.
- Wrap retry logic so each retry constructs the Blob anew instead of reusing it.
- Use blob.toBlobDescriptor()/digest once and cache the descriptor rather than re-reading the stream.
Example fix
// before Blob blob = Blobs.from(inputStream); blob.writeTo(out1); blob.writeTo(out2); // IllegalStateException // after byte[] bytes = ByteStreams.toByteArray(inputStream); Blob blob = Blobs.from(bytes); // replayable blob.writeTo(out1); blob.writeTo(out2);
Defensive patterns
Strategy: fallback
Validate before calling
null
Type guard
null
Try / catch
try { blob.writeTo(out); } catch (IllegalStateException e) { /* blob was stream-backed and already consumed; rebuild blob */ } Prevention
- Prefer byte[]/Path-backed Blobs when content may be written more than once
- Create a new InputStreamBlob per write attempt in retry loops
- Compute the descriptor once and cache it (toBlobDescriptor) instead of re-reading
- Never pass raw request InputStreams into blobs you might reuse
When it happens
Trigger: Calling blob.writeTo(outputStream) twice on the same Blob created from an InputStream (e.g. via Blobs.from(InputStream)); retry logic that replays a failed upload by re-writing the same Blob; logging code that inspects content before the real upload.
Common situations: HTTP upload retries in RegistryClient flows reusing the same blob; piping a Blob both to a digest computation and then to the network; caching a Blob built from a request body InputStream and reusing it across attempts.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
AI-assisted analysis of GoogleContainerTools/jib@fb949e2676 (2026-09-06).
Data as JSON: /api/errors/eeb2c050c0d798cb.
Report an issue: GitHub.