square/okhttp · error · IOException

Unexpected code

Error message

Unexpected code 

What it means

Thrown in the Moshi-parsing recipe: `if (!response.isSuccessful()) throw new IOException("Unexpected code " + response)`. The call hits a specific GitHub Gist by ID. If the gist was deleted, never existed, or the unauthenticated rate limit is exceeded, GitHub returns non-2xx and this throws before Moshi ever sees the body.

Solutions

  1. Verify the gist ID still exists (open it in a browser or curl -I the URL).
  2. Swap in a gist ID you control for a stable demo.
  3. Add a GitHub token to avoid 403 rate limiting.
  4. Branch on response.code(); only call gistJsonAdapter.fromJson on success.

Example fix

// before
if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);
Gist gist = gistJsonAdapter.fromJson(response.body().source());

// after
if (!response.isSuccessful()) {
  throw new IOException("Cannot fetch gist: HTTP " + response.code());
}
Gist gist = gistJsonAdapter.fromJson(response.body().source());
Defensive patterns

Strategy: validation

Validate before calling

// Validate status before Moshi parses; only parse on success.
try (Response response = client.newCall(request).execute()) {
  if (response.code() == 404) { /* gist gone */ return; }
  if (!response.isSuccessful()) { throw new IOException("gist HTTP " + response.code()); }
  Gist gist = gistJsonAdapter.fromJson(response.body().source());
}

Type guard

static boolean parseable(Response r) { return r.isSuccessful() && r.body() != null; }

Try / catch

try {
  // call + parse
} catch (IOException e) {
  // status failure ('Unexpected code') or transport
} catch (JsonDataException e) {
  // Moshi could not map the body to Gist (different concern; parse, not status)
}

Prevention

When it happens

Trigger: GET https://api.github.com/gists/c2a7c39532239ff261be returns 404 (gist deleted/never existed), 403 (rate limit), or 410. The hardcoded gist ID was a real sample at authoring time but may no longer exist.

Common situations: The sample gist ID was deleted by its owner; rate-limited unauthenticated GitHub access; copy-pasting without swapping in your own gist ID; GitHub API deprecation returning a different shape.

Related errors


AI-assisted analysis of square/okhttp@91a8b34c6f (2026-08-10). Data as JSON: /api/errors/564427a7175aa22e. Report an issue: GitHub.

Appendix: source

Thrown at samples/guide/src/main/java/okhttp3/recipes/ParseResponseWithMoshi.java:36

import com.squareup.moshi.JsonAdapter;
import com.squareup.moshi.Moshi;
import java.io.IOException;
import java.util.Map;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;

public final class ParseResponseWithMoshi {
  private final OkHttpClient client = new OkHttpClient();
  private final Moshi moshi = new Moshi.Builder().build();
  private final JsonAdapter<Gist> gistJsonAdapter = moshi.adapter(Gist.class);

  public void run() throws Exception {
    Request request = new Request.Builder()
        .url("https://api.github.com/gists/c2a7c39532239ff261be")
        .build();
    try (Response response = client.newCall(request).execute()) {
      if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);

      Gist gist = gistJsonAdapter.fromJson(response.body().source());

      for (Map.Entry<String, GistFile> entry : gist.files.entrySet()) {
        System.out.println(entry.getKey());
        System.out.println(entry.getValue().content);
      }
    }
  }

  static class Gist {
    Map<String, GistFile> files;
  }

  static class GistFile {
    String content;
  }

View on GitHub (pinned to 91a8b34c6f)