square/okhttp · error · IOException

Unexpected code

Error message

Unexpected code 

What it means

Recipe-level guard after POSTing a pipe-backed RequestBody to GitHub's markdown/raw endpoint. A separate 'writer' thread feeds the pipe (Okio Pipe of 8192 bytes) while the request thread reads from it in writeTo(). If the server's final HTTP response is non-2xx, java.io.IOException("Unexpected code " + response) is thrown. If the writer thread dies (IOException/InterruptedException in streamPrimesToSinkAsynchronously) the pipe stalls and execute() throws a different IOException, not this line.

Source

Thrown at samples/guide/src/main/java/okhttp3/recipes/PostStreamingWithPipe.java:45

public final class PostStreamingWithPipe {
  public static final MediaType MEDIA_TYPE_MARKDOWN
      = MediaType.get("text/x-markdown; charset=utf-8");

  private final OkHttpClient client = new OkHttpClient();

  public void run() throws Exception {
    final PipeBody pipeBody = new PipeBody();

    Request request = new Request.Builder()
        .url("https://api.github.com/markdown/raw")
        .post(pipeBody)
        .build();

    streamPrimesToSinkAsynchronously(pipeBody.sink());

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

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

  private void streamPrimesToSinkAsynchronously(final BufferedSink sink) {
    Thread thread = new Thread("writer") {
      @Override public void run() {
        try {
          sink.writeUtf8("Numbers\n");
          sink.writeUtf8("-------\n");
          for (int i = 2; i <= 997; i++) {
            System.out.println(i);
            Thread.sleep(10);
            sink.writeUtf8(String.format(" * %s = %s\n", i, factor(i)));
          }
          sink.close();
        } catch (IOException | InterruptedException e) {

View on GitHub (pinned to 4fc0831380)

Solutions

  1. Ensure the writer thread always closes the sink in a finally block so a stalled pipe cannot hang execute().
  2. Inspect response.code() when you do reach this line; treat as a normal HTTP error.
  3. Authenticate to GitHub and verify the content-type.

Example fix

// before (writer thread)
try {
  ... sink.writeUtf8(...); Thread.sleep(10); ...
  sink.close();
} catch (IOException | InterruptedException e) {
  e.printStackTrace();
}

// after
try {
  ... sink.writeUtf8(...); ...
} catch (IOException | InterruptedException e) {
  e.printStackTrace();
} finally {
  try { sink.close(); } catch (IOException ignored) {}
}
// and at the response guard:
try (Response response = client.newCall(request).execute()) {
  if (!response.isSuccessful()) {
    throw new IOException("GitHub " + response.code() + " after streamed upload");
  }
  ...
}
Defensive patterns

Strategy: try-catch

Validate before calling

// Ensure the writer thread always closes the sink so a stalled pipe cannot hang execute()
Thread writer = new Thread(() -> {
  try (BufferedSink s = sink) {  // try-with-resources guarantees close
    // ...write payload...
  } catch (IOException e) {
    log.warn("writer failed", e);
  }
}, "writer");
writer.setDaemon(true);
writer.start();

Try / catch

try (Response response = client.newCall(request).execute()) {
  if (!response.isSuccessful()) {
    throw new HttpException(response.code(), response.message());
  }
} catch (IOException e) {
  // a crashed/unclosed writer thread surfaces here as a pipe stall / connection reset
  if (writerThread.getState() == Thread.State.TERMINATED) {
    throw new UploadStallException("writer thread died before closing pipe", e);
  }
  throw e;
}

Prevention

When it happens

Trigger: POST https://api.github.com/markdown/raw with a PipeBody while a writer thread calls sink.writeUtf8(...)+sink.close(). Reaches this line when both threads cooperated and the upload completed but GitHub returned 4xx/5xx (403 rate limit, 415 media type). A writer-thread crash surfaces as a stuck pipe / connection-reset IOException earlier.

Common situations: Writer thread hits InterruptedException (Thread.sleep interrupted) and prints stack trace but does not close the sink cleanly → the request never completes and execute() blocks/fails instead of reaching this line; GitHub rate limiting; mismatched content-type.

Related errors


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