square/okhttp · error · IOException

Unexpected code

Error message

Unexpected code 

What it means

Recipe-level guard after POSTing a fixed String (markdown releases list) as text/x-markdown to GitHub's markdown/raw endpoint. If the response is non-2xx, java.io.IOException("Unexpected code " + response) is thrown. This is the simplest of the POST recipes — no file IO, no streaming — so reaching this line means the request was sent and the server replied with an error status.

Source

Thrown at samples/guide/src/main/java/okhttp3/recipes/PostString.java:46

  private final OkHttpClient client = new OkHttpClient();

  public void run() throws Exception {
    String postBody = ""
        + "Releases\n"
        + "--------\n"
        + "\n"
        + " * _1.0_ May 6, 2013\n"
        + " * _1.1_ June 15, 2013\n"
        + " * _1.2_ August 11, 2013\n";

    Request request = new Request.Builder()
        .url("https://api.github.com/markdown/raw")
        .post(RequestBody.create(postBody, MEDIA_TYPE_MARKDOWN))
        .build();

    try (Response response = client.newCall(request).execute()) {
      if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);

      System.out.println(response.body().string());
    }
  }

  public static void main(String... args) throws Exception {
    new PostString().run();
  }
}

View on GitHub (pinned to 4fc0831380)

Solutions

  1. Check response.code() and X-RateLimit-* headers.
  2. Authenticate the request with a token.
  3. Ensure MEDIA_TYPE is text/x-markdown; charset=utf-8.
  4. Add a User-Agent header.

Example fix

// before
try (Response response = client.newCall(request).execute()) {
  if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);
  ...
}

// after
Request request = new Request.Builder()
    .url("https://api.github.com/markdown/raw")
    .header("Authorization", "Bearer " + token)
    .header("User-Agent", "MyApp/1.0")
    .post(RequestBody.create(postBody, MEDIA_TYPE_MARKDOWN))
    .build();
try (Response response = client.newCall(request).execute()) {
  if (!response.isSuccessful()) {
    throw new IOException("GitHub " + response.code()
        + " remaining=" + response.header("X-RateLimit-Remaining"));
  }
  ...
}
Defensive patterns

Strategy: validation

Validate before calling

// Authenticate, set UA, and verify media type before posting
String token = System.getenv("GITHUB_TOKEN");
MediaType mediaType = MediaType.get("text/x-markdown; charset=utf-8");
Request request = new Request.Builder()
    .url("https://api.github.com/markdown/raw")
    .header("Authorization", token != null ? "Bearer " + token : null)
    .header("User-Agent", "MyApp/1.0")
    .post(RequestBody.create(postBody, mediaType))
    .build();

Try / catch

try (Response response = client.newCall(request).execute()) {
  if (!response.isSuccessful()) {
    if (response.code() == 415) throw new UnsupportedMediaTypeException("Expected text/x-markdown");
    if (response.code() == 403) throw new RateLimitedException(response.header("X-RateLimit-Reset"));
    throw new HttpException(response.code(), response.message());
  }
}

Prevention

When it happens

Trigger: POST https://api.github.com/markdown/raw with RequestBody.create(postBody, MEDIA_TYPE_MARKDOWN). Fires on 403 (unauthenticated rate limit), 415 (media type wrong), 404/410 (endpoint gone), 400 (body not valid markdown the endpoint expects).

Common situations: GitHub unauthenticated rate limit (60/hr) when iterating; changing MEDIA_TYPE to a value GitHub rejects; endpoint behaviour changed; missing User-Agent.

Related errors


AI-assisted analysis of square/okhttp@4fc0831380 (2026-08-04). Data as JSON: /data/errors/ff1f21b7742d3696.json. Report an issue: GitHub.