{"record":{"id":"500954d40d7dc143","repo":"square/okhttp","slug":"unexpected-code-500954","errorCode":null,"errorMessage":"Unexpected code ","messagePattern":"Unexpected code ","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"error","filePath":"samples/guide/src/main/java/okhttp3/recipes/SynchronousGet.java","lineNumber":33,"sourceCode":" */\npackage okhttp3.recipes;\n\nimport java.io.IOException;\nimport okhttp3.Headers;\nimport okhttp3.OkHttpClient;\nimport okhttp3.Request;\nimport okhttp3.Response;\n\npublic final class SynchronousGet {\n  private final OkHttpClient client = new OkHttpClient();\n\n  public void run() throws Exception {\n    Request request = new Request.Builder()\n        .url(\"https://publicobject.com/helloworld.txt\")\n        .build();\n\n    try (Response response = client.newCall(request).execute()) {\n      if (!response.isSuccessful()) throw new IOException(\"Unexpected code \" + response);\n\n      Headers responseHeaders = response.headers();\n      for (int i = 0; i < responseHeaders.size(); i++) {\n        System.out.println(responseHeaders.name(i) + \": \" + responseHeaders.value(i));\n      }\n\n      System.out.println(response.body().string());\n    }\n  }\n\n  public static void main(String... args) throws Exception {\n    new SynchronousGet().run();\n  }\n}\n","sourceCodeStart":15,"sourceCodeEnd":48,"githubUrl":"https://github.com/square/okhttp/blob/91a8b34c6f44bd28c421364f8edadc9f324dddd9/samples/guide/src/main/java/okhttp3/recipes/SynchronousGet.java#L15-L48","documentation":"The canonical OkHttp 'Synchronous Get' recipe: after `client.newCall(request).execute()`, the code calls `response.isSuccessful()` and throws `IOException(\"Unexpected code \" + response)` for any non-2xx status before printing headers and body. This is the most minimal form of the idiom and the one most often copy-pasted.","triggerScenarios":"A GET to `https://publicobject.com/helloworld.txt` returns non-2xx: 404 if the path/file is moved or removed, 451/403 under geo or WAF blocks, 500/502/503 during origin outages, or 407 if a proxy demands authentication. DNS/TLS/connection failures throw a different exception (e.g. `UnknownHostException`, `SSLHandshakeException`) before this line is reached; the `Unexpected code` throw is purely an HTTP-status outcome.","commonSituations":"Hard-coded external sample URL going offline or being reorganized; running in a restricted network where the host is blocked; copy-pasting the recipe as production error handling and treating any 3xx-not-followed or 4xx as a crash; not realizing OkHttp follows redirects/30x by default so this line rarely fires for redirects.","solutions":["Open the URL in a browser or with `curl -I` to confirm it still returns 200; if not, point the recipe at a URL you control.","Replace the blanket throw with a switch on `response.code()` so 4xx is reported distinctly from 5xx and you can retry only 5xx/429.","If the host is behind a proxy, configure `.proxy(...)` or `ProxySelector` on the `OkHttpClient` builder.","For production code, distinguish transport errors (`IOException` from `execute()`) from HTTP-status errors (this throw) so they can be handled with different policies."],"exampleFix":"// before\ntry (Response response = client.newCall(request).execute()) {\n  if (!response.isSuccessful()) throw new IOException(\"Unexpected code \" + response);\n  ...\n}\n\n// after\ntry (Response response = client.newCall(request).execute()) {\n  int code = response.code();\n  if (code >= 200 && code < 300) {\n    // success path: read headers + body\n  } else if (code >= 500 || code == 429) {\n    throw new IOException(\"Transient server error \" + code + \" for \" + request.url());\n  } else {\n    throw new IOException(\"Client error \" + code + \" \" + response.message()\n        + \" for \" + request.url());\n  }\n}","handlingStrategy":"try-catch","validationCode":"// Pre-flight: cheap reachability check (optional) so you fail before the call.\nURI uri = URI.create(\"https://publicobject.com/helloworld.txt\");\ntry {\n  InetAddress.getAllByName(uri.getHost()); // throws if DNS dead\n} catch (UnknownHostException e) {\n  throw new IllegalStateException(\"Cannot resolve \" + uri.getHost(), e);\n}\n\n// Post-call: classify instead of blanket-throw.\ntry (Response response = client.newCall(request).execute()) {\n  int c = response.code();\n  if (c >= 200 && c < 300) {\n    // read headers + body\n  } else if (c == 404) {\n    throw new ContentMissingException(uri);\n  } else if (c >= 500 || c == 429) {\n    throw new TransientHttpException(c, response.header(\"Retry-After\"));\n  } else {\n    throw new IOException(\"HTTP \" + c + \" \" + response.message());\n  }\n}","typeGuard":"private static boolean isBodyReadable(Response r) {\n  return r.isSuccessful() && r.body() != null;\n}\nprivate static boolean isTransient(int code) {\n  return code == 429 || (code >= 500 && code < 600);\n}","tryCatchPattern":"int attempts = 0;\nwhile (true) {\n  try (Response response = client.newCall(request).execute()) {\n    if (response.isSuccessful()) {\n      // read body\n      break;\n    }\n    if (!isTransient(response.code())) {\n      throw new IOException(\"Non-retryable HTTP \" + response.code());\n    }\n    // transient: honor Retry-After if present, exponential backoff otherwise\n    long backoff = Math.min(30_000L, 500L * (1L << attempts));\n    Thread.sleep(backoff);\n  } catch (IOException e) {\n    // transport failure — also retryable on transient conditions\n    if (++attempts > MAX_ATTEMPTS) throw e;\n  }\n}","preventionTips":["Replace the blanket `!isSuccessful()` throw with explicit handling per status class (2xx/3xx/4xx/5xx).","Retry only transient failures (5xx, 429) with bounded exponential backoff; do not retry 4xx.","Treat DNS/TLS errors (thrown by `execute()`) separately from HTTP-status outcomes.","For long-lived URLs you don't control, add a fallback URL or graceful degradation."],"tags":["okhttp","java","http-status","synchronous-get","error-handling"],"backgroundTag":null,"analyzedSha":"91a8b34c6f44bd28c421364f8edadc9f324dddd9","analyzedAt":"2026-08-10T18:39:54.316Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}