{"id":"a69f9973cf4d3782","repo":"square/okhttp","slug":"unexpected-code-a69f99","errorCode":null,"errorMessage":"Unexpected code ","messagePattern":"Unexpected code ","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"error","filePath":"samples/guide/src/main/java/okhttp3/recipes/PreemptiveAuth.java","lineNumber":41,"sourceCode":"import okhttp3.Response;\n\npublic final class PreemptiveAuth {\n  private final OkHttpClient client;\n\n  public PreemptiveAuth() {\n    client = new OkHttpClient.Builder()\n        .addInterceptor(\n            new BasicAuthInterceptor(\"publicobject.com\", \"jesse\", \"password1\"))\n        .build();\n  }\n\n  public void run() throws Exception {\n    Request request = new Request.Builder()\n        .url(\"https://publicobject.com/secrets/hellosecret.txt\")\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(response.body().string());\n    }\n  }\n\n  public static void main(String... args) throws Exception {\n    new PreemptiveAuth().run();\n  }\n\n  static final class BasicAuthInterceptor implements Interceptor {\n    private final String credentials;\n    private final String host;\n\n    BasicAuthInterceptor(String host, String username, String password) {\n      this.credentials = Credentials.basic(username, password);\n      this.host = host;\n    }\n","sourceCodeStart":23,"sourceCodeEnd":59,"githubUrl":"https://github.com/square/okhttp/blob/4fc083138014aba3d0078f5c26d1ce84815fa984/samples/guide/src/main/java/okhttp3/recipes/PreemptiveAuth.java#L23-L59","documentation":"Recipe-level guard after a GET configured with a preemptive Basic auth interceptor (BasicAuthInterceptor adds Authorization: Basic <creds> for host publicobject.com before the request goes out). Because auth is sent on the first request (not after a 401 challenge), a wrong credential yields a final 401 that reaches this line, where java.io.IOException(\"Unexpected code \" + response) is thrown.","triggerScenarios":"GET https://publicobject.com/secrets/hellosecret.txt with an always-on Authorization header. Fires on 401 (wrong username/password), 403 (authenticated but forbidden), or 404 (resource gone). Because the interceptor only injects the header when request.url().host() equals 'publicobject.com', a host mismatch silently sends no auth and you can still get 401.","commonSituations":"Placeholder credentials 'jesse/password1' do not match the target; host check is case-sensitive — a URL with uppercase host or a trailing-dot host (publicobject.com.) will not match and auth is omitted; sending Basic over http leaks credentials.","solutions":["Verify the credentials are valid for the realm.","Make the host comparison robust: request.url().host().equalsIgnoreCase(host).","Use https:// so the preemptive header is encrypted.","Inspect response.code() to distinguish 401 (creds) from 403 (forbidden) from 404 (missing)."],"exampleFix":"// before\nif (request.url().host().equals(host)) {\n  request = request.newBuilder().header(\"Authorization\", credentials).build();\n}\n...\nif (!response.isSuccessful()) throw new IOException(\"Unexpected code \" + response);\n\n// after\nif (request.url().host().equalsIgnoreCase(host)) {\n  request = request.newBuilder().header(\"Authorization\", credentials).build();\n}\n...\nif (response.code() == 401) {\n  throw new IOException(\"Preemptive auth rejected for \" + request.url());\n}\nif (!response.isSuccessful()) {\n  throw new IOException(\"HTTP \" + response.code() + \" for \" + request.url());\n}","handlingStrategy":"validation","validationCode":"// Make host matching robust and verify credentials before relying on the request\n// inside the interceptor:\nif (request.url().host().equalsIgnoreCase(host)) {\n  request = request.newBuilder().header(\"Authorization\", credentials).build();\n}\n// before calling, sanity-check:\nif (username == null || password == null) throw new IllegalArgumentException(\"creds required\");\n// prefer https so the header is encrypted","typeGuard":null,"tryCatchPattern":"try (Response response = client.newCall(request).execute()) {\n  if (response.code() == 401) throw new AuthException(\"Preemptive Basic rejected for \" + request.url());\n  if (response.code() == 403) throw new ForbiddenException(request.url().toString());\n  if (!response.isSuccessful()) throw new HttpException(response.code(), response.message());\n}","preventionTips":["Compare hosts case-insensitively (equalsIgnoreCase).","Use https:// when sending preemptive Basic credentials.","Confirm credentials against the server's realm before deploying.","Restrict the interceptor to the exact host to avoid leaking credentials to other domains."],"tags":["okhttp","http-status","authentication","preemptive-auth","basic-auth","interceptor","java"],"analyzedSha":"4fc083138014aba3d0078f5c26d1ce84815fa984","analyzedAt":"2026-08-04T19:09:04.639Z","schemaVersion":2}