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
- Replace or wrap the underlying stream with BufferedInputStream, whose skip reliably advances or blocks.
- If skipping to EOF fails, fall back to reading and discarding n bytes in a loop.
- Check that available() reflects reality; a stalled network stream may report 0.
- 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
- Wrap raw/network streams in BufferedInputStream before APNG parsing — its skip blocks until satisfied.
- Avoid streams whose skip() returns 0 when data remains.
- For large skips, prefer read-and-discard loops over skip().
- Test the APNG decoder against socket-backed streams, not just files.
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
- Theme-pack asset source is not a regular file:
- Theme pack directory does not contain
- Theme pack does not contain
- Invalid theme-pack manifest
- Cannot export a background directory as a theme-pack asset
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)