jwtk/jjwt · error · java.io.IOException

IO Exception ${t.getMessage()}

Error message

IO Exception ${t.getMessage()}

What it means

FilteredOutputStream wraps any non-IOException Throwable raised by write, flush, or close on its delegate into an IOException with the message 'IO Exception <msg>'. IOExceptions from the delegate are rethrown as-is.

Source

Thrown at impl/src/main/java/io/jsonwebtoken/impl/io/FilteredOutputStream.java:124

        try {
            out.flush();
        } catch (final Throwable t) {
            onThrowable(t);
        }
    }

    /**
     * Handle any IOExceptions thrown.
     * <p>
     * This method provides a point to implement custom exception
     * handling. The default behavior is to re-throw the exception.
     *
     * @param t The Throwable thrown
     * @throws IOException if an I/O error occurs.
     */
    protected void onThrowable(final Throwable t) throws IOException {
        if (t instanceof IOException) throw (IOException) t;
        throw new IOException("IO Exception " + t.getMessage(), t);
    }

    /**
     * Invokes the delegate's {@code write(byte[])} method.
     *
     * @param bts the bytes to write
     * @throws IOException if an I/O error occurs.
     */
    @Override
    public void write(final byte[] bts) throws IOException {
        try {
            final int len = Bytes.length(bts);
            beforeWrite(len);
            out.write(bts);
            afterWrite(len);
        } catch (final Throwable t) {
            onThrowable(t);
        }

View on GitHub (pinned to fb71496164)

Solutions

  1. Inspect the cause: native IOExceptions surface unchanged, so fix the underlying IO problem.
  2. Ensure the output stream remains open until all writes and the final flush complete.
  3. Check flush()/close() ordering — close the stream exactly once, in a finally block or try-with-resources.
  4. For socket-backed streams, handle broken-pipe conditions on the transport layer.

Example fix

// before
out.write(bytes);
out.flush();
// after
try (OutputStream out = ...) {
    out.write(bytes);
    out.flush();
} // closes exactly once, even on failure
Defensive patterns

Strategy: try-catch

Validate before calling

// Java
if (out == null) throw new IllegalArgumentException("OutputStream cannot be null");
// avoid writing to already-committed servlet responses
if (response != null && response.isCommitted()) throw new IllegalStateException("response committed");

Try / catch

try {
    filteredOut.write(bytes);
    filteredOut.flush();
} catch (IOException e) {
    Throwable cause = e.getCause();
    if (cause != null) log.error("Write failure root cause: {}", cause.getMessage());
    throw e;
}

Prevention

When it happens

Trigger: Writing, flushing, or closing a FilteredOutputStream whose delegate throws a non-IO Throwable (e.g. NullPointerException from an unset delegate, RuntimeException in a custom stream) or an underlying IO error.

Common situations: Output stream closed by the framework before all writes complete; broken pipe on socket-backed streams; flush() on a stream whose target (e.g. HTTP response) is already committed.

Understand the failure class

Background: "failed to write file", "Could not save figure", "Error saving remote file" — file write failed: causes and fixes across languages and libraries — this error's family across 38 libraries.

Related errors


AI-assisted analysis of jwtk/jjwt@fb71496164 (2026-09-09). Data as JSON: /api/errors/c3141ad34814710c. Report an issue: GitHub.