{"id":"5253a33b7189f984","repo":"square/okhttp","slug":"unexpected-code-5253a3","errorCode":null,"errorMessage":"Unexpected code ","messagePattern":"Unexpected code ","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"error","filePath":"samples/guide/src/main/java/okhttp3/recipes/AsynchronousGet.java","lineNumber":42,"sourceCode":"import okhttp3.Response;\nimport okhttp3.ResponseBody;\n\npublic final class AsynchronousGet {\n  private final OkHttpClient client = new OkHttpClient();\n\n  public void run() throws Exception {\n    Request request = new Request.Builder()\n        .url(\"http://publicobject.com/helloworld.txt\")\n        .build();\n\n    client.newCall(request).enqueue(new Callback() {\n      @Override public void onFailure(Call call, IOException e) {\n        e.printStackTrace();\n      }\n\n      @Override public void onResponse(Call call, Response response) throws IOException {\n        try (ResponseBody responseBody = response.body()) {\n          if (!response.isSuccessful()) throw new IOException(\"Unexpected code \" + response);\n\n          Headers responseHeaders = response.headers();\n          for (int i = 0, size = responseHeaders.size(); i < size; i++) {\n            System.out.println(responseHeaders.name(i) + \": \" + responseHeaders.value(i));\n          }\n\n          System.out.println(responseBody.string());\n        }\n      }\n    });\n  }\n\n  public static void main(String... args) throws Exception {\n    new AsynchronousGet().run();\n  }\n}\n","sourceCodeStart":24,"sourceCodeEnd":59,"githubUrl":"https://github.com/square/okhttp/blob/4fc083138014aba3d0078f5c26d1ce84815fa984/samples/guide/src/main/java/okhttp3/recipes/AsynchronousGet.java#L24-L59","documentation":"Recipe-level guard inside the asynchronous Callback.onResponse: after the call succeeds at the transport layer, response.isSuccessful() is checked and a java.io.IOException(\"Unexpected code \" + response) is thrown for non-2xx status. Because this runs on OkHttp's dispatcher thread, the exception is not propagated to your code — it is logged and swallowed by the Callback contract unless you handle it. Throwing inside onResponse defeats the purpose of onFailure, which is only invoked for transport failures (no connection, no response).","triggerScenarios":"client.newCall(request).enqueue(callback) against http://publicobject.com/helloworld.txt. Fires when the server returns 3xx not followed, 4xx, or 5xx — e.g. the site redirects http→https (handled by default), the path is gone (404), or the host is parked/changed (403/451). A network failure instead goes to onFailure, never reaching this line.","commonSituations":"publicobject.com being a moving target (the recipe domain has changed ownership/status over time); copying enqueue() code expecting throws to surface in the caller (they won't — the callback thread eats them); using http:// (not https) and hitting an ISP/hosting redirect page that returns 200 HTML, masking the issue.","solutions":["Do not throw inside onResponse — log response.code() and surface the error via your own error callback or a CompletableFuture.completeExceptionally(...).","Verify the URL still resolves to the expected plaintext document (curl it).","If the body is unexpected, also check response.body().contentType() and contentLength().","Use https:// instead of http:// to avoid redirect/parked-page surprises."],"exampleFix":"// before\n@Override public void onResponse(Call call, Response response) throws IOException {\n  try (ResponseBody responseBody = response.body()) {\n    if (!response.isSuccessful()) throw new IOException(\"Unexpected code \" + response);\n    ...\n  }\n}\n\n// after\n@Override public void onResponse(Call call, Response response) throws IOException {\n  try (ResponseBody responseBody = response.body()) {\n    if (!response.isSuccessful()) {\n      resultFuture.completeExceptionally(\n          new IOException(\"HTTP \" + response.code() + \" for \" + response.request().url()));\n      return;\n    }\n    ...\n  }\n}","handlingStrategy":"validation","validationCode":"// Surface async errors via a future instead of throwing on the dispatcher thread\nCompletableFuture<String> future = new CompletableFuture<>();\nclient.newCall(request).enqueue(new Callback() {\n  @Override public void onFailure(Call call, IOException e) { future.completeExceptionally(e); }\n  @Override public void onResponse(Call call, Response response) throws IOException {\n    try (ResponseBody body = response.body()) {\n      if (!response.isSuccessful()) {\n        future.completeExceptionally(new HttpException(response.code(), response.request().url().toString()));\n        return;\n      }\n      future.complete(body.string());\n    }\n  }\n});","typeGuard":null,"tryCatchPattern":"// Callback-based: do NOT throw inside onResponse\n@Override public void onResponse(Call call, Response response) throws IOException {\n  try (ResponseBody body = response.body()) {\n    if (!response.isSuccessful()) {\n      errorHandler.accept(new HttpException(response.code(), response.request().url().toString()));\n      return;\n    }\n    successHandler.accept(body.string());\n  }\n}","preventionTips":["Never throw inside Callback.onResponse expecting the caller to see it — use onFailure semantics or a CompletableFuture.","Use https:// to avoid redirect/parked-page responses.","Verify the URL still serves the expected content before relying on it.","Distinguish transport failures (onFailure) from HTTP errors (onResponse non-2xx)."],"tags":["okhttp","http-status","async","callback","java"],"analyzedSha":"4fc083138014aba3d0078f5c26d1ce84815fa984","analyzedAt":"2026-08-04T19:09:04.639Z","schemaVersion":2}