HMCL-dev/HMCL · error · IOException

Failed to skip a total of bytes in stream; bytes remained…

Error message

Failed to skip a total of  bytes in stream;  bytes remained but  returned from skip.

What it means

InputStreamSlice.skip must advance the underlying stream by exactly n bytes (bounded by available()); when src.skip returns 0 or negative the stream cannot make progress (some streams return 0 instead of blocking or skipping), so skip throws IOException. Note the message literally reads 'Failed to skip a total of bytes... ' with numbers inserted — the format is correct in source, only the concatenation layout looks odd in the reported text.

Solutions

  1. Replace or wrap the underlying stream with BufferedInputStream, whose skip reliably advances or blocks.
  2. If skipping to EOF fails, fall back to reading and discarding n bytes in a loop.
  3. Check that available() reflects reality; a stalled network stream may report 0.
  4. For custom streams, fix skip() to block or return -1 at EOF rather than 0.

Example fix

// before: stream with unreliable skip
slice.skip(chunkLength); // IOException: Failed to skip...
// after: wrap in BufferedInputStream
InputStream buffered = new BufferedInputStream(raw, 8192);
PngSource source = new PngStreamSource(buffered);
Defensive patterns

Strategy: fallback

Validate before calling

// avoid unreliable skip: buffer the stream up front
InputStream safe = raw.markSupported()
    ? raw
    : new BufferedInputStream(raw, 8192);

Try / catch

try {
  slice.skip(n);
} catch (IOException e) {
  // fallback: read-and-discard, or re-open stream buffered
  InputStream buffered = new BufferedInputStream(reopen(), 8192);
  drain(buffered, n); // read() into scratch buffer n times
}

Prevention

When it happens

Trigger: Calling skip on an InputStreamSlice whose underlying stream's skip() returns 0 — e.g. a non-blocking or already-exhausted stream, or streams (some network/decoder streams) that return 0 instead of skipping when remaining > 0.

Common situations: Piping PNG data from a socket stream whose skip is unimplemented; skipping more than available on a stalled stream; custom InputStream with a broken skip implementation feeding the APNG reader.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


AI-assisted analysis of HMCL-dev/HMCL@24702dc5a0 (2026-09-10). Data as JSON: /api/errors/e0894deb5df7e89a. Report an issue: GitHub.

Appendix: source

Thrown at HMCL/src/main/java/org/jackhuang/hmcl/ui/image/apng/util/InputStreamSlice.java:64

        int rv = src.read(b, off, Math.min(len, length - position));
        if (rv > 0) {
            position += rv;
        }
        return rv;
    }

    @Override
    public long skip(long n) throws IOException {
        if (atEof || position >= length) {
            atEof = true;
            return -1;
        }
        n = Math.min(available(), n); // calculate maximum skip
        long remaining = n;
        while (remaining > 0) {
            long skipped = src.skip(remaining); // attempt to skip that much
            if (skipped <= 0) {
                throw new IOException("Failed to skip a total of " + n + " bytes in stream; " + remaining + " bytes remained but " + skipped + " returned from skip.");
            }
            remaining -= skipped;
        }
        position += n; // adjust position by correct skip
        return n;
    }

    @Override
    public int available() throws IOException {
        if (atEof || position >= length) {
            return 0;
        }
        return length - position;
    }

    @Override
    public int read() throws IOException {
        if (atEof || position >= length) {

View on GitHub (pinned to 24702dc5a0)