GoogleContainerTools/jib · error · IOException

Cannot run Jib in offline mode; local Jib cache for base ima

Error message

Cannot run Jib in offline mode; local Jib cache for base image is missing image layer <layerDigest>. Rerun Jib in online mode with "-Djib.alwaysCacheBaseImage=true" to re-download the base image layers.

What it means

In offline mode Jib cannot download base image layers. When a base image layer digest is not present in the local Jib cache and the build is offline, ObtainBaseImageLayerStep.call throws IOException telling the user to rerun online (optionally with -Djib.alwaysCacheBaseImage=true) so layers are persisted in the project cache. This prevents builds from silently producing images missing layers.

Source

Thrown at jib-core/src/main/java/com/google/cloud/tools/jib/builder/steps/ObtainBaseImageLayerStep.java:129

      StateInTarget stateInTarget = blobExistenceChecker.check(layerDigest);
      if (stateInTarget == StateInTarget.EXISTING) {
        eventHandlers.dispatch(
            LogEvent.info(
                "Skipping pull; BLOB already exists on target registry : "
                    + layer.getBlobDescriptor()));
        return new PreparedLayer.Builder(layer).setStateInTarget(stateInTarget).build();
      }

      Cache cache = buildContext.getBaseImageLayersCache();

      // Checks if the layer already exists in the cache.
      Optional<CachedLayer> optionalCachedLayer = cache.retrieve(layerDigest);
      if (optionalCachedLayer.isPresent()) {
        CachedLayer cachedLayer = optionalCachedLayer.get();
        return new PreparedLayer.Builder(cachedLayer).setStateInTarget(stateInTarget).build();
      } else if (buildContext.isOffline()) {
        throw new IOException(
            "Cannot run Jib in offline mode; local Jib cache for base image is missing image layer "
                + layerDigest
                + ". Rerun Jib in online mode with \"-Djib.alwaysCacheBaseImage=true\" to "
                + "re-download the base image layers.");
      }

      try (ThrottledProgressEventDispatcherWrapper progressEventDispatcherWrapper =
          new ThrottledProgressEventDispatcherWrapper(
              progressEventDispatcher.newChildProducer(),
              "pulling base image layer " + layerDigest)) {
        CachedLayer cachedLayer =
            cache.writeCompressedLayer(
                Verify.verifyNotNull(registryClient)
                    .pullBlob(
                        layerDigest,
                        progressEventDispatcherWrapper::setProgressTarget,
                        progressEventDispatcherWrapper::dispatchProgress));
        return new PreparedLayer.Builder(cachedLayer).setStateInTarget(stateInTarget).build();

View on GitHub (pinned to fb949e2676)

Solutions

  1. Rerun once with network access: remove --offline / set jib.offline=false, and add -Djib.alwaysCacheBaseImage=true to populate the persistent cache, then go offline again.
  2. Pin/use a base image whose layers are already in the local cache (previously downloaded).
  3. Warm the cache on a connected machine and copy the Jib cache directory to the offline environment.
  4. If available, build from a Docker daemon image (docker daemonizer or docker:// tar path) whose layers don't need the Jib cache.
  5. Restore the base image layers by re-running the same build online with the same base image tag/digest.

Example fix

// before (CI, offline runner)
./gradlew jibBuild --offline
// after
./gradlew jibBuild -Djib.alwaysCacheBaseImage=true   // once, online, to warm cache
// subsequent offline builds
./gradlew jibBuild --offline
Defensive patterns

Strategy: retry

Validate before calling

// Check cache before going offline
for (String digest : baseImageLayerDigests) {
  if (cache.retrieve(digest).isEmpty()) throw new IllegalStateException("warm cache online first: " + digest);
}

Type guard

null

Try / catch

try { /* offline build */ } catch (IOException e) {
  if (e.getMessage().contains("offline mode")) { /* rerun online with -Djib.alwaysCacheBaseImage=true, then retry offline */ }
  else throw e;
}

Prevention

When it happens

Trigger: Running with `--offline=true` (or jib.offline=true) while the local cache lacks a layer of the base image - e.g. the base image digest changed upstream, the cache was cleared, or a pinned digest was never downloaded on this machine.

Common situations: CI jobs run in network-isolated sandboxes after cache eviction; air-gapped environments switching base image tags so the cached layers no longer match; using `docker://` metadata flows expecting the Jib cache (not the Docker daemon cache); first build on a new machine with --offline.

Understand the failure class

Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.

Related errors


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