square/okhttp · error · IOException

Unexpected code

Error message

Unexpected code 

What it means

Recipe-level guard on the FIRST of two identical GETs that demonstrate HTTP caching. The client is built with a 10 MiB disk Cache; on the first request the cache is cold so the response must come from the network. If that network response is not 2xx, java.io.IOException("Unexpected code " + response1) is thrown before the cache is populated.

Source

Thrown at samples/guide/src/main/java/okhttp3/recipes/CacheResponse.java:44

  private final OkHttpClient client;

  public CacheResponse(File cacheDirectory) throws Exception {
    int cacheSize = 10 * 1024 * 1024; // 10 MiB
    Cache cache = new Cache(cacheDirectory, cacheSize);

    client = new OkHttpClient.Builder()
        .cache(cache)
        .build();
  }

  public void run() throws Exception {
    Request request = new Request.Builder()
        .url("http://publicobject.com/helloworld.txt")
        .build();

    String response1Body;
    try (Response response1 = client.newCall(request).execute()) {
      if (!response1.isSuccessful()) throw new IOException("Unexpected code " + response1);

      response1Body = response1.body().string();
      System.out.println("Response 1 response:          " + response1);
      System.out.println("Response 1 cache response:    " + response1.cacheResponse());
      System.out.println("Response 1 network response:  " + response1.networkResponse());
    }

    String response2Body;
    try (Response response2 = client.newCall(request).execute()) {
      if (!response2.isSuccessful()) throw new IOException("Unexpected code " + response2);

      response2Body = response2.body().string();
      System.out.println("Response 2 response:          " + response2);
      System.out.println("Response 2 cache response:    " + response2.cacheResponse());
      System.out.println("Response 2 network response:  " + response2.networkResponse());
    }

    System.out.println("Response 2 equals Response 1? " + response1Body.equals(response2Body));

View on GitHub (pinned to 4fc0831380)

Solutions

  1. Check response1.code(), response1.cacheResponse(), and response1.networkResponse() to determine whether it was a network round-trip and what the origin said.
  2. Verify the cache directory exists and is writable; check Cache.directory() and Cache.size() after the call.
  3. Confirm the URL is reachable with curl; the cache only helps once the origin is healthy.
  4. Use https:// to avoid redirect-related status codes.

Example fix

// before
try (Response response1 = client.newCall(request).execute()) {
  if (!response1.isSuccessful()) throw new IOException("Unexpected code " + response1);
  ...
}

// after
try (Response response1 = client.newCall(request).execute()) {
  if (!response1.isSuccessful()) {
    throw new IOException("Warm-up failed: HTTP " + response1.code()
        + " network=" + response1.networkResponse()
        + " cache=" + response1.cacheResponse());
  }
  ...
}
Defensive patterns

Strategy: validation

Validate before calling

// Verify cache directory is writable before constructing the client
File dir = cacheDirectory;
if (!dir.exists() && !dir.mkdirs()) throw new IOException("Cannot create cache dir: " + dir);
if (!dir.canWrite()) throw new IOException("Cache dir not writable: " + dir);
Cache cache = new Cache(dir, 10 * 1024 * 1024);
OkHttpClient client = new OkHttpClient.Builder().cache(cache).build();

Try / catch

try (Response response1 = client.newCall(request).execute()) {
  if (!response1.isSuccessful()) {
    throw new HttpException(response1.code(),
        "network=" + response1.networkResponse() + ", cache=" + response1.cacheResponse());
  }
  // warm the cache
}

Prevention

When it happens

Trigger: First client.newCall(request).execute() for http://publicobject.com/helloworld.txt with caching enabled. Fires on any non-2xx from the origin: host down (would actually be transport IOException, not this), 404, 503, or a non-cacheable error. Because this is the cache-warming request, failure here means the second request (error [4]) cannot be a cache hit either.

Common situations: Cache directory not writable (separate failure: the cache silently no-ops or throws earlier); origin server returning 5xx; running offline and expecting the cache to serve stale content (OkHttp does not serve stale-on-error unless a separate fallback is configured); the demo domain returning a redirect to https.

Related errors


AI-assisted analysis of square/okhttp@4fc0831380 (2026-08-04). Data as JSON: /data/errors/b446fa9fd3bcbf8d.json. Report an issue: GitHub.