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
- Check response.code() and X-RateLimit-* headers.
- Authenticate the request with a token.
- Ensure MEDIA_TYPE is text/x-markdown; charset=utf-8.
- 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
- Authenticate GitHub POSTs with a Bearer token to avoid the 60/hr cap.
- Always set the media type to text/x-markdown; charset=utf-8.
- Send a User-Agent header.
- Branch on response.code() rather than a single throw.
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.