{"record":{"id":"e0894deb5df7e89a","repo":"HMCL-dev/HMCL","slug":"failed-to-skip-a-total-of-bytes-in-stream-bytes","errorCode":null,"errorMessage":"Failed to skip a total of  bytes in stream;  bytes remained but  returned from skip.","messagePattern":"Failed to skip a total of  bytes in stream;  bytes remained but  returned from skip\\.","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"error","filePath":"HMCL/src/main/java/org/jackhuang/hmcl/ui/image/apng/util/InputStreamSlice.java","lineNumber":64,"sourceCode":"        int rv = src.read(b, off, Math.min(len, length - position));\n        if (rv > 0) {\n            position += rv;\n        }\n        return rv;\n    }\n\n    @Override\n    public long skip(long n) throws IOException {\n        if (atEof || position >= length) {\n            atEof = true;\n            return -1;\n        }\n        n = Math.min(available(), n); // calculate maximum skip\n        long remaining = n;\n        while (remaining > 0) {\n            long skipped = src.skip(remaining); // attempt to skip that much\n            if (skipped <= 0) {\n                throw new IOException(\"Failed to skip a total of \" + n + \" bytes in stream; \" + remaining + \" bytes remained but \" + skipped + \" returned from skip.\");\n            }\n            remaining -= skipped;\n        }\n        position += n; // adjust position by correct skip\n        return n;\n    }\n\n    @Override\n    public int available() throws IOException {\n        if (atEof || position >= length) {\n            return 0;\n        }\n        return length - position;\n    }\n\n    @Override\n    public int read() throws IOException {\n        if (atEof || position >= length) {","sourceCodeStart":46,"sourceCodeEnd":82,"githubUrl":"https://github.com/HMCL-dev/HMCL/blob/24702dc5a0214034f4c27166d5fd30cad08cec19/HMCL/src/main/java/org/jackhuang/hmcl/ui/image/apng/util/InputStreamSlice.java#L46-L82","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before: stream with unreliable skip\nslice.skip(chunkLength); // IOException: Failed to skip...\n// after: wrap in BufferedInputStream\nInputStream buffered = new BufferedInputStream(raw, 8192);\nPngSource source = new PngStreamSource(buffered);","handlingStrategy":"fallback","validationCode":"// avoid unreliable skip: buffer the stream up front\nInputStream safe = raw.markSupported()\n    ? raw\n    : new BufferedInputStream(raw, 8192);","typeGuard":null,"tryCatchPattern":"try {\n  slice.skip(n);\n} catch (IOException e) {\n  // fallback: read-and-discard, or re-open stream buffered\n  InputStream buffered = new BufferedInputStream(reopen(), 8192);\n  drain(buffered, n); // read() into scratch buffer n times\n}","preventionTips":["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."],"tags":["io","stream","skip"],"backgroundTag":"unsupported-operation","analyzedSha":"24702dc5a0214034f4c27166d5fd30cad08cec19","analyzedAt":"2026-09-10T12:36:46.680Z","contentChangedAt":"2026-09-10T12:36:46.680Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}