apache/flink · error · IOException

Unable to write to output stream.

Error message

Unable to write to output stream.

What it means

IOUtils.copyBytes treats the output stream specially when it is a PrintStream: PrintStream swallows I/O errors, so after each write the code calls ps.checkError() and throws IOException("Unable to write to output stream.") if the underlying stream failed. Without this the copy would silently produce truncated output.

Source

Thrown at flink-core/src/main/java/org/apache/flink/util/IOUtils.java:66

     * @param out OutputStream to write to
     * @param buffSize the size of the buffer
     * @param close whether or not close the InputStream and OutputStream at the end. The streams
     *     are closed in the finally clause.
     * @throws IOException thrown if an error occurred while writing to the output stream
     */
    public static void copyBytes(
            final InputStream in, final OutputStream out, final int buffSize, final boolean close)
            throws IOException {

        @SuppressWarnings("resource")
        final PrintStream ps = out instanceof PrintStream ? (PrintStream) out : null;
        final byte[] buf = new byte[buffSize];
        try {
            int bytesRead = in.read(buf);
            while (bytesRead >= 0) {
                out.write(buf, 0, bytesRead);
                if ((ps != null) && ps.checkError()) {
                    throw new IOException("Unable to write to output stream.");
                }
                bytesRead = in.read(buf);
            }
        } finally {
            if (close) {
                out.close();
                in.close();
            }
        }
    }

    /**
     * Copies from one stream to another. <strong>closes the input and output streams at the
     * end</strong>.
     *
     * @param in InputStream to read from
     * @param out OutputStream to write to
     * @throws IOException thrown if an I/O error occurs while copying

View on GitHub (pinned to 2f3c205e92)

Solutions

  1. Check what consumed the process stdout — a closed pipe on the reader side is the usual cause; keep the consumer alive or buffer output
  2. Write to a regular FileOutputStream/BufferedOutputStream instead of a PrintStream so failures surface as normal IOExceptions with a cause
  3. If truncation is acceptable (e.g. piping into head), catch this IOException and ignore it deliberately

Example fix

// before
IOUtils.copyBytes(in, System.out, 4096, false);
// after (failures carry a real cause)
try (OutputStream out = new BufferedOutputStream(new FileOutputStream(file))) {
    IOUtils.copyBytes(in, out, 4096, true);
}
Defensive patterns

Strategy: try-catch

Try / catch

try { IOUtils.copyBytes(in, System.out, 4096, false); } catch (IOException e) { /* reader closed the pipe (e.g. | head): exit quietly */ }

Prevention

When it happens

Trigger: Calling IOUtils.copyBytes with System.out/System.err or another PrintStream as destination whose sink has failed — e.g. the pipe reading the process output closed (head/broken less), a redirected stdout to a full/closed file, or a dead terminal on the other end.

Common situations: CLI jobs piping Flink output into `head`, log redirection where the disk filled, running in containers where stdout is drained by a logger daemon that died.

Related errors


AI-assisted analysis of apache/flink@2f3c205e92 (2026-08-14). Data as JSON: /api/errors/a57edade899677a6. Report an issue: GitHub.