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
TarExtractor.extract throws IllegalStateException when reproducible timestamps are requested but the destination directory already exists and is non-empty. Reproducible extraction requires writing into a fresh location so entry order/timestamps are deterministic; Jib fails fast rather than mixing old and new content.
Source
Thrown at jib-core/src/main/java/com/google/cloud/tools/jib/tar/TarExtractor.java:67
extract(source, destination, false);
}
/**
* Extracts a tarball to the specified destination.
*
* @param source the tarball to extract
* @param destination the output directory
* @param enableReproducibleTimestamps whether or not reproducible timestamps should be used
* @throws IOException if extraction fails
* @throws IllegalStateException when reproducible timestamps are enabled but the target root used
* for extracting the tar contents is not empty
*/
public static void extract(Path source, 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<TarArchiveEntry> entries = new ArrayList<>();
try (InputStream in = new BufferedInputStream(Files.newInputStream(source));
TarArchiveInputStream tarArchiveInputStream = new TarArchiveInputStream(in)) {
for (TarArchiveEntry entry = tarArchiveInputStream.getNextEntry();
entry != null;
entry = tarArchiveInputStream.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 " + source;
throw new IOException("Blocked unzipping files outside destination: " + offender);
}
if (entry.isDirectory()) {View on GitHub (pinned to fb949e2676)
Solutions
- Delete or empty the destination directory before calling extract with enableReproducibleTimestamps=true.
- Pass enableReproducibleTimestamps=false if merging into an existing directory is intentional.
- Extract to a fresh temporary directory each run.
- Add cleanup to your build script (e.g. gradle clean or rm -rf dest).
Example fix
// before TarExtractor.extract(tarPath, dest, true); // after Files.walkFileTree(dest, deleteVisitor); // or FileUtils.deleteDirectory(dest) TarExtractor.extract(tarPath, dest, true);
Defensive patterns
Strategy: validation
Validate before calling
// Ensure destination is fresh before reproducible extraction
if (java.nio.file.Files.isDirectory(dest)
&& java.util.Objects.requireNonNull(dest.toFile().list()).length > 0) {
throw new IllegalArgumentException("Destination must be empty: " + dest);
} Try / catch
try { TarExtractor.extract(src, dest, true); } catch (IllegalStateException e) { org.apache.commons.io.FileUtils.deleteDirectory(dest.toFile()); TarExtractor.extract(src, dest, true); } Prevention
- Clean the destination before each reproducible extraction.
- Extract into a new temp directory per run.
- Pass enableReproducibleTimestamps=false for in-place merges.
- Add a pre-build cleanup step to scripts/CI.
When it happens
Trigger: Calling TarExtractor.extract(source, destination, true) where destination is an existing directory containing files; re-running extraction into the same folder with enableReproducibleTimestamps=true.
Common situations: Re-running a build/extraction script without cleaning the target dir; extracting layers into a cached workspace that already has prior contents.
Related errors
- Unable to create cache directory for project path: ${path} -
- Missing option: --name must be specified when using --target
- Cannot create FileLayers from non-file, non-directory: ${src
- ${src} is not a parent of ${path}
- NoSuchFileException: <directory>
AI-assisted analysis of GoogleContainerTools/jib@fb949e2676 (2026-09-06).
Data as JSON: /api/errors/adeeb022f27f61e5.
Report an issue: GitHub.