GoogleContainerTools/jib · error · CacheCorruptedException

No or multiple layer files found for layer hash

Error message

No or multiple layer files found for layer hash <layerDigest> in directory: <layerDirectory>

What it means

Cached layers are stored one compressed layer file per digest directory. retrieve(layerDigest) lists the layer directory and requires exactly one layer file; zero files (missing layer) or more than one (duplicate) means the cache is inconsistent, and CacheCorruptedException is thrown naming the digest and directory.

Solutions

  1. Delete the affected layer directory (or the whole cache) so the layer is re-fetched
  2. Disable concurrent Jib builds sharing one cache directory, or give each a separate cache
  3. Exclude the cache directory from antivirus scanning and cleanup jobs
  4. Re-run the build after clearing ~/.cache/google-cloud-tools-java/jib

Example fix

// before: build fails on layer sha256:abc...
// after: remove just that layer
rm -rf ~/.cache/google-cloud-tools-java/jib/layers/sha256:abc...
Defensive patterns

Strategy: try-catch

Validate before calling

long n = Files.list(layerDir).filter(Files::isRegularFile).count();
if (n != 1) deleteRecursively(layerDir);

Try / catch

try {
  build();
} catch (CacheCorruptedException e) {
  String dir = extractLayerDir(e.getMessage());
  if (dir != null) deleteRecursively(Path.of(dir)); else wipeCache();
  build();
}

Prevention

When it happens

Trigger: CacheStorageReader.retrieve() is called (during layer push/pull flows) and Files.list(layerDirectory) filtered by CacheStorageFiles::isLayerFile yields a count other than 1.

Common situations: Antivirus or cleanup tools deleting cache files, two Jib processes writing the same layer concurrently, partial download interrupted leaving zero/extra files, manually copying files into the cache.

Related errors


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

Appendix: source

Thrown at jib-core/src/main/java/com/google/cloud/tools/jib/cache/CacheStorageReader.java:160

   * Retrieves the {@link CachedLayer} for the layer with digest {@code layerDigest}.
   *
   * @param layerDigest the layer digest
   * @return the {@link CachedLayer} referenced by the layer digest, if found
   * @throws CacheCorruptedException if the cache was found to be corrupted
   * @throws IOException if an I/O exception occurs
   */
  Optional<CachedLayer> retrieve(DescriptorDigest layerDigest)
      throws IOException, CacheCorruptedException {
    Path layerDirectory = cacheStorageFiles.getLayerDirectory(layerDigest);
    if (!Files.exists(layerDirectory)) {
      return Optional.empty();
    }

    try (Stream<Path> files = Files.list(layerDirectory)) {
      List<Path> layerFiles =
          files.filter(CacheStorageFiles::isLayerFile).collect(Collectors.toList());
      if (layerFiles.size() != 1) {
        throw new CacheCorruptedException(
            cacheStorageFiles.getCacheDirectory(),
            "No or multiple layer files found for layer hash "
                + layerDigest.getHash()
                + " in directory: "
                + layerDirectory);
      }

      Path layerFile = layerFiles.get(0);
      return Optional.of(
          CachedLayer.builder()
              .setLayerDigest(layerDigest)
              .setLayerSize(Files.size(layerFile))
              .setLayerBlob(Blobs.from(layerFile))
              .setLayerDiffId(cacheStorageFiles.getDigestFromFilename(layerFile))
              .build());
    }
  }

View on GitHub (pinned to fb949e2676)