GoogleContainerTools/jib · error · IllegalStateException
Cannot enable reproducible timestamps. They can only be enab
Error message
Cannot enable reproducible timestamps. They can only be enabled when the target root doesn't exist or is an empty directory
What it means
ZipUtil.unzip refuses to extract into a destination when enableReproducibleTimestamps is true and the destination is an existing non-empty directory, because reproducible extraction requires a clean target. It throws IllegalStateException 'Cannot enable reproducible timestamps. They can only be enabled when the target root doesn't exist or is an empty directory'.
Source
Thrown at jib-plugins-common/src/main/java/com/google/cloud/tools/jib/plugins/common/ZipUtil.java:66
unzip(archive, destination, false);
}
/**
* Unzips {@code archive} into {@code destination}.
*
* @param archive zip archive to unzip
* @param destination target root for unzipping
* @param enableReproducibleTimestamps whether or not reproducible timestamps should be used
* @throws IOException when I/O error occurs
* @throws IllegalStateException when reproducible timestamps are enabled but the target root used
* for unzipping is not empty
*/
public static void unzip(Path archive, Path destination, boolean enableReproducibleTimestamps)
throws IOException {
if (enableReproducibleTimestamps
&& Files.isDirectory(destination)
&& destination.toFile().list().length != 0) {
throw new IllegalStateException(
"Cannot enable reproducible timestamps. They can only be enabled when the target root doesn't exist or is an empty directory");
}
String canonicalDestination = destination.toFile().getCanonicalPath();
List<ZipEntry> entries = new ArrayList<>();
try (InputStream fileIn = new BufferedInputStream(Files.newInputStream(archive));
ZipInputStream zipIn = new ZipInputStream(fileIn)) {
for (ZipEntry entry = zipIn.getNextEntry(); entry != null; entry = zipIn.getNextEntry()) {
entries.add(entry);
Path entryPath = destination.resolve(entry.getName());
String canonicalTarget = entryPath.toFile().getCanonicalPath();
if (!canonicalTarget.startsWith(canonicalDestination + File.separator)) {
String offender = entry.getName() + " from " + archive;
throw new IOException("Blocked unzipping files outside destination: " + offender);
}
if (entry.isDirectory()) {
Files.createDirectories(entryPath);View on GitHub (pinned to fb949e2676)
Solutions
- Delete the destination directory (or its contents) before calling unzip, e.g. with Jib's File deleter or Files.walk cleanup.
- Extract to a fresh temporary directory each run and swap it in afterwards.
- Pass enableReproducibleTimestamps=false only if reproducibility is not required and overwriting is acceptable.
Example fix
// before
ZipUtil.unzip(jarPath, targetDir, true);
// after
if (Files.isDirectory(targetDir)) {
try (Stream<Path> walk = Files.walk(targetDir)) {
walk.sorted(Comparator.reverseOrder()).forEach(p -> p.toFile().delete());
}
}
ZipUtil.unzip(jarPath, targetDir, true); Defensive patterns
Strategy: try-catch
Validate before calling
// Ensure destination is absent or empty before unzip
if (Files.isDirectory(destination)
&& destination.toFile().list() != null
&& destination.toFile().list().length > 0) {
throw new IllegalStateException("destination not empty: " + destination);
} Try / catch
try {
ZipUtil.unzip(archive, destination, true);
} catch (IllegalStateException e) {
// destination is a non-empty dir: clean it and retry
FileUtils.deleteDirectory(destination.toFile());
ZipUtil.unzip(archive, destination, true);
} Prevention
- Clean the target directory (or use a fresh temp dir) before every unzip
- Never reuse an extraction directory across builds with reproducible timestamps enabled
- Add a clean step to CI before exploded-jar extraction
When it happens
Trigger: Calling ZipUtil.unzip(archive, destination, true) where Files.isDirectory(destination) is true and destination.toFile().list().length != 0 — i.e. the target directory already contains files.
Common situations: Re-running a build that previously unpacked a dependency JAR (e.g. dependency-reduced exploded jars) into the same target directory; a stale or partially-cleaned build directory being reused; scripts reusing a shared extraction dir across builds.
Related errors
- Blocked unzipping files outside destination: ${entryName} fr
- Cannot enable reproducible timestamps. They can only be enab
- platform configuration is missing an OS value
- ${path}
- ${appRoot}
AI-assisted analysis of GoogleContainerTools/jib@fb949e2676 (2026-09-06).
Data as JSON: /api/errors/4a2340e86f6c98cc.
Report an issue: GitHub.