jwtk/jjwt · error · java.io.IOException

IO Exception: ${t.getMessage()}

Error message

IO Exception: ${t.getMessage()}

What it means

FilteredInputStream wraps any non-IOException Throwable raised by its delegate stream operations (read, skip, available, close, reset) into an IOException with the message 'IO Exception: <msg>'. If the original is already an IOException it is rethrown unchanged.

Source

Thrown at impl/src/main/java/io/jsonwebtoken/impl/io/FilteredInputStream.java:137

            super.close();
        } catch (Throwable t) {
            onThrowable(t);
        }
    }

    /**
     * Handle any Throwable thrown; by default, throws the given exception.
     * <p>
     * This method provides a point to implement custom exception
     * handling. The default behavior is to re-throw the exception.
     * </p>
     *
     * @param t The IOException 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 mark(int)} method.
     *
     * @param readlimit read ahead limit
     */
    @Override
    public synchronized void mark(final int readlimit) {
        in.mark(readlimit);
    }

    /**
     * Invokes the delegate's {@code markSupported()} method.
     *
     * @return true if mark is supported, otherwise false
     */
    @Override

View on GitHub (pinned to fb71496164)

Solutions

  1. Inspect the exception cause: if it is already an IOException, handle that error directly.
  2. Call markSupported() before calling reset(); guard against unsupported reset.
  3. Ensure the underlying stream (file, socket) is open and available for the whole read.
  4. Wrap custom delegate stream code so unchecked exceptions don't leak into IO operations.

Example fix

// before
in.reset(); // throws IOException if mark not supported
// after
if (in.markSupported()) { in.reset(); } else { throw new IllegalStateException("reset not supported"); }
Defensive patterns

Strategy: try-catch

Validate before calling

// Java
if (in == null) throw new IllegalArgumentException("InputStream cannot be null");
if (wantReset && !in.markSupported()) throw new IllegalStateException("reset unsupported");

Type guard

static boolean supportsReset(InputStream in) {
    return in != null && in.markSupported();
}

Try / catch

try {
    int n = filteredIn.read(buf);
} catch (IOException e) {
    Throwable cause = e.getCause();
    if (cause instanceof RuntimeException) throw (RuntimeException) cause;
    throw e;
}

Prevention

When it happens

Trigger: Any read/skip/available/close/reset call on a FilteredInputStream whose delegate throws (e.g. a RuntimeException from a custom stream, or a non-IO Throwable during stream processing).

Common situations: Custom delegate streams throwing unchecked exceptions; streams over sockets that break mid-read; reset() called when the delegate does not support marking (markSupported() false).

Understand the failure class

Background: "failed to read file", EACCES, ENOENT and "could not read <path>" errors: when a program can't read a file from disk — this error's family across 49 libraries.

Related errors


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