{"record":{"id":"cb977d990cba03b3","repo":"square/okhttp","slug":"unexpected-code","errorCode":null,"errorMessage":"Unexpected code ","messagePattern":"Unexpected code ","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"error","filePath":"samples/guide/src/main/java/okhttp3/recipes/AccessHeaders.java","lineNumber":35,"sourceCode":"\nimport java.io.IOException;\nimport okhttp3.OkHttpClient;\nimport okhttp3.Request;\nimport okhttp3.Response;\n\npublic final class AccessHeaders {\n  private final OkHttpClient client = new OkHttpClient();\n\n  public void run() throws Exception {\n    Request request = new Request.Builder()\n        .url(\"https://api.github.com/repos/lysine-dev/okhttp/issues\")\n        .header(\"User-Agent\", \"OkHttp Headers.java\")\n        .addHeader(\"Accept\", \"application/json; q=0.5\")\n        .addHeader(\"Accept\", \"application/vnd.github.v3+json\")\n        .build();\n\n    try (Response response = client.newCall(request).execute()) {\n      if (!response.isSuccessful()) throw new IOException(\"Unexpected code \" + response);\n\n      System.out.println(\"Server: \" + response.header(\"Server\"));\n      System.out.println(\"Date: \" + response.header(\"Date\"));\n      System.out.println(\"Vary: \" + response.headers(\"Vary\"));\n    }\n  }\n\n  public static void main(String... args) throws Exception {\n    new AccessHeaders().run();\n  }\n}\n","sourceCodeStart":17,"sourceCodeEnd":47,"githubUrl":"https://github.com/square/okhttp/blob/91a8b34c6f44bd28c421364f8edadc9f324dddd9/samples/guide/src/main/java/okhttp3/recipes/AccessHeaders.java#L17-L47","documentation":"Thrown by the recipe's own guard: `if (!response.isSuccessful()) throw new IOException(\"Unexpected code \" + response)`. OkHttp deliberately does NOT throw for HTTP error status codes (4xx/5xx); it returns them as Response objects so the application can decide. `response.isSuccessful()` is true only when `code` is in 200..299. This IOException therefore fires whenever the GitHub API answers with anything outside the 2xx range.","triggerScenarios":"GET to https://api.github.com/repos/lysine-dev/okhttp/issues returns a non-2xx code. Concretely: 404 when the repo 'lysine-dev/okhttp' does not exist or was renamed; 301/302 redirect to the canonical URL (OkHttp follows redirects by default, but a final non-2xx still triggers this); 403 when the unauthenticated GitHub rate limit (60 req/hour/IP) is exceeded; 451 for legal blocks.","commonSituations":"Repo was deleted or renamed; missing/wrong User-Agent header (GitHub requires one); hitting the low unauthenticated rate limit; copying this sample against a repo that does not exist; GitHub API versioning change returning 410 Gone.","solutions":["Read response.code() and response.body() before throwing to see the exact status and GitHub error message.","Point the URL at a repo that actually exists, or use the generic 'repos/{owner}/{name}' path for your own repo.","Add an OAuth/token Authorization header (or authenticator) to raise the GitHub rate limit if you are getting 403.","Keep the custom User-Agent header shown in the sample; GitHub rejects requests without one.","Switch from throwing to branching on the code so 3xx/4xx can be handled explicitly."],"exampleFix":"// before\nif (!response.isSuccessful()) throw new IOException(\"Unexpected code \" + response);\n\n// after\nif (response.code() == 404) {\n  System.err.println(\"Repo not found: \" + response.request().url());\n  return;\n}\nif (!response.isSuccessful()) {\n  throw new IOException(\"HTTP \" + response.code() + \": \" + response.body().string());\n}","handlingStrategy":"validation","validationCode":"// Validate BEFORE consuming the body: branch on the code rather than throwing blindly.\ntry (Response response = client.newCall(request).execute()) {\n  int code = response.code();\n  if (code == 404) { /* missing repo */ return; }\n  if (code == 403 || code == 429) { /* rate limited; back off / add token */ return; }\n  if (!response.isSuccessful()) {\n    throw new IOException(\"GitHub HTTP \" + code + \": \" + response.body().string());\n  }\n  // safe to use body\n}","typeGuard":"// Java has no runtime type guards; narrow on status instead.\nstatic boolean isUsable(Response r) { return r.isSuccessful(); }","tryCatchPattern":"try {\n  // request + response handling\n} catch (IOException e) {\n  // Includes the 'Unexpected code' throw plus transport errors; inspect e.getMessage()\n  if (e.getMessage() != null && e.getMessage().startsWith(\"Unexpected code\")) {\n    // HTTP-status originated from your own guard\n  }\n}","preventionTips":["Never treat OkHttp Response objects as success without checking isSuccessful()/code().","Add Authorization tokens for rate-limited APIs like GitHub.","Always set a descriptive User-Agent for GitHub requests.","Log response.code() and body before throwing so failures are diagnosable."],"tags":["okhttp","http-status","github-api","rate-limit","java"],"backgroundTag":null,"analyzedSha":"91a8b34c6f44bd28c421364f8edadc9f324dddd9","analyzedAt":"2026-08-10T18:39:54.316Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}