apache/beam · error · IOException

Stream has been finished. Can not write any more data.

Error message

Stream has been finished. Can not write any more data.

What it means

The single-byte write(int b) of BufferedElementCountingOutputStream refuses output once the stream has been finished, throwing IOException('Stream has been finished. Can not write any more data.'). This enforces one-shot usage semantics after finish() to prevent corrupt output blocks.

Source

Thrown at sdks/java/core/src/main/java/org/apache/beam/sdk/util/BufferedElementCountingOutputStream.java:142

    }
    finished = true;
  }

  /**
   * Marks that a new element is being output. This allows this output stream to use the buffer if
   * it had previously overflowed marking the start of a new block of elements.
   */
  public void markElementStart() throws IOException {
    if (finished) {
      throw new IOException("Stream has been finished. Can not add any more elements.");
    }
    count++;
  }

  @Override
  public void write(int b) throws IOException {
    if (finished) {
      throw new IOException("Stream has been finished. Can not write any more data.");
    }
    if (count == 0) {
      os.write(b);
      return;
    }

    if (buffer.hasRemaining()) {
      buffer.put((byte) b);
    } else {
      outputBuffer();
      os.write(b);
    }
  }

  @Override
  public void write(byte[] b, int off, int len) throws IOException {
    if (finished) {
      throw new IOException("Stream has been finished. Can not write any more data.");

View on GitHub (pinned to 12126d8942)

Solutions

  1. Write all bytes before calling finish(); reorder so finish() is the last operation.
  2. Instantiate a fresh BufferedElementCountingOutputStream for any data written after a finish.
  3. Guard writes with an isFinished/finished flag or try-catch IOException to detect premature writes in wrapper code.

Example fix

// before
stream.write(headerByte);
stream.finish();
stream.write(trailerByte); // IOException
// after
stream.write(headerByte);
stream.write(trailerByte);
stream.finish();
Defensive patterns

Strategy: validation

Validate before calling

if (stream.finished) throw new IllegalStateException("stream already finished");

Try / catch

try {
  stream.write(b);
} catch (IOException e) {
  if (e.getMessage().contains("finished")) { /* replace stream */ }
}

Prevention

When it happens

Trigger: Calling write(int) after finish() — for example writing trailing bytes after a flush-and-finish, or reusing a finished stream for a new element.

Common situations: Loop code that finishes the stream inside the loop then keeps writing; retry logic re-attempting writes on a closed stream; misordered cleanup where finish() is invoked before all payload bytes are emitted.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


AI-assisted analysis of apache/beam@12126d8942 (2026-09-13). Data as JSON: /api/errors/3a0fb7985c995ba5. Report an issue: GitHub.