apache/hadoop · error · IOException

this stream is already closed

Error message

this stream is already closed

What it means

CachingBlockManager.get(blockNumber) re-checks the manager's closed flag on every iteration of its retry loop; if the owning prefetch stream was closed while get() is still running (typically from another thread), it aborts with IOException("this stream is already closed") rather than returning data.

Source

Thrown at hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/impl/prefetch/CachingBlockManager.java:156

  /**
   * Gets the block having the given {@code blockNumber}.
   *
   * @throws IllegalArgumentException if blockNumber is negative.
   */
  @Override
  public BufferData get(int blockNumber) throws IOException {
    checkNotNegative(blockNumber, "blockNumber");

    BufferData data;
    final int maxRetryDelayMs = bufferPoolSize * 120 * 1000;
    final int statusUpdateDelayMs = 120 * 1000;
    Retryer retryer = new Retryer(10, maxRetryDelayMs, statusUpdateDelayMs);
    boolean done;

    do {
      if (closed) {
        throw new IOException("this stream is already closed");
      }

      data = bufferPool.acquire(blockNumber);
      done = getInternal(data);

      if (retryer.updateStatus()) {
        LOG.warn("waiting to get block: {}", blockNumber);
        LOG.info("state = {}", this.toString());
      }
    }
    while (!done && retryer.continueRetry());

    if (done) {
      return data;
    } else {
      String message = String.format("Wait failed for get(%d)", blockNumber);
      throw new IllegalStateException(message);
    }

View on GitHub (pinned to 2add963021)

Solutions

  1. Give the stream a single owner: only the owner closes, and only after readers finish
  2. In cancellation paths, signal readers to stop and join them before closing
  3. Treat this IOException in reader threads as a cancellation signal, not a data error
  4. Open a separate stream per thread instead of sharing one

Example fix

// before
new Thread(() -> { try { in.read(); } catch (IOException e) { /* ... */ } }).start();
in.close();            // racing reader -> "this stream is already closed"

// after
Thread reader = new Thread(() -> { try { in.read(); } catch (IOException e) { /* ... */ } });
reader.start();
reader.join();         // reader finished before close
in.close();
Defensive patterns

Strategy: try-catch

Try / catch

in reader threads, catch IOException with message "this stream is already closed" and interpret it as cancellation/shutdown — exit the reader cleanly instead of reporting a data error.

Prevention

When it happens

Trigger: One thread closes the prefetch input stream while another is blocked in read()/get() waiting for a block; task cancellation closing inputs mid-read; watchdog code closing "stuck" streams that are merely waiting on a slow block fetch.

Common situations: Sharing one stream across threads without a close handshake; MR/Spark task-kill paths closing inputs while reader threads drain; timeout-driven cleanup racing legitimate slow reads.

Related errors


AI-assisted analysis of apache/hadoop@2add963021 (2026-08-22). Data as JSON: /api/errors/ee7b70c452565360. Report an issue: GitHub.