GoogleContainerTools/jib · error · UnexpectedBlobDigestException

The pulled BLOB has digest '${receivedDigest}', but the requ

Error message

The pulled BLOB has digest '${receivedDigest}', but the request digest was '${requestedDigest}'

What it means

BlobPuller verifies that the BLOB downloaded from the registry matches the digest that was requested. When the computed digest of the streamed response body differs from the requested blobDigest, it throws UnexpectedBlobDigestException. This protects against corrupted, truncated, or tampered downloads.

Source

Thrown at jib-core/src/main/java/com/google/cloud/tools/jib/registry/BlobPuller.java:75

      Consumer<Long> writtenByteCountListener) {
    this.registryEndpointRequestProperties = registryEndpointRequestProperties;
    this.blobDigest = blobDigest;
    this.destinationOutputStream = destinationOutputStream;
    this.blobSizeListener = blobSizeListener;
    this.writtenByteCountListener = writtenByteCountListener;
  }

  @Override
  public Void handleResponse(Response response) throws IOException, UnexpectedBlobDigestException {
    blobSizeListener.accept(response.getContentLength());

    try (OutputStream outputStream =
        new NotifyingOutputStream(destinationOutputStream, writtenByteCountListener)) {
      BlobDescriptor receivedBlobDescriptor =
          Digests.computeDigest(response.getBody(), outputStream);

      if (!blobDigest.equals(receivedBlobDescriptor.getDigest())) {
        throw new UnexpectedBlobDigestException(
            "The pulled BLOB has digest '"
                + receivedBlobDescriptor.getDigest()
                + "', but the request digest was '"
                + blobDigest
                + "'");
      }
    }

    return null;
  }

  @Override
  @Nullable
  public BlobHttpContent getContent() {
    return null;
  }

  @Override

View on GitHub (pinned to fb949e2676)

Solutions

  1. Retry the pull; transient proxy/CDN corruption is often intermittent
  2. Clear or bypass intermediary caches (HTTP proxy, registry mirror) and pull again
  3. Verify the manifest digest referenced actually exists in the registry (re-push the image if it was partially uploaded)
  4. Check network stability / TLS interception devices that may alter bytes

Example fix

// before: pulling through a flaky mirror
RegistryClient client = new RegistryClient(null, "mirror.example.com", "my/repo", eventHandlers);
client.pullBlob(digest, consumer, writer);
// after: pull from the authoritative registry and retry on digest mismatch
RegistryClient client = new RegistryClient(null, "registry-1.docker.io", "my/repo", eventHandlers);
try {
  client.pullBlob(digest, consumer, writer);
} catch (UnexpectedBlobDigestException e) {
  client.pullBlob(digest, consumer, writer); // retry once
}
Defensive patterns

Strategy: retry

Validate before calling

// verify digest locally if you already have the bytes
Digests.computeDigest(blob).getDigest().equals(expectedDigest)

Try / catch

try { client.pullBlob(digest, sink, out); } catch (UnexpectedBlobDigestException e) { log.warn("digest mismatch, retrying"); client.pullBlob(digest, sink, out); }

Prevention

When it happens

Trigger: Calling BlobPuller.handleResponse with a registry response whose body hashes to a digest different from the blobDigest requested in the pull.

Common situations: A proxy or transparent cache corrupts or truncates the layer download; the registry serves a different layer than referenced (mis-cached CDN edge); a MITM or storage corruption in the registry backend.

Understand the failure class

Background: Checksum mismatch errors: "checksum verification failed", "digest mismatch", "expected vs actual checksum" — what they mean and how to fix them — this error's family across 41 libraries.

Related errors


AI-assisted analysis of GoogleContainerTools/jib@fb949e2676 (2026-09-06). Data as JSON: /api/errors/c908970bddf9ace9. Report an issue: GitHub.