{"record":{"id":"e7c2ce9f64bb6989","repo":"theonedev/onedev","slug":"skipped-only","errorCode":null,"errorMessage":"Skipped only ","messagePattern":"Skipped only ","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"error","filePath":"server-core/src/main/java/io/onedev/server/util/IOUtils.java","lineNumber":22,"sourceCode":"import java.io.InputStream;\nimport java.io.OutputStream;\n\n@SuppressWarnings(\"deprecation\")\npublic class IOUtils extends org.apache.commons.io.IOUtils {\n\n\tpublic static final int BUFFER_SIZE = 64*1024;\n\n\tpublic static void copyRange(InputStream in, OutputStream out, LongRange range) throws IOException {\n\t\tint totalSkipped = 0;\n\t\twhile (totalSkipped < range.getStart())\t {\n\t\t\tlong skipped = in.skip(range.getStart()-totalSkipped);\n\t\t\tif (skipped == 0)\n\t\t\t\tbreak;\n\t\t\ttotalSkipped += skipped;\n\t\t}\n\t\t\n\t\tif (totalSkipped < range.getStart()) \n\t\t\tthrow new IOException(\"Skipped only \" + totalSkipped + \" bytes out of \" + range.getStart() + \" required.\");\n\n\t\tlong bytesToCopy = range.getEnd() - range.getStart() + 1;\n\n\t\tbyte buffer[] = new byte[BUFFER_SIZE];\n\t\twhile (bytesToCopy > 0) {\n\t\t\tint bytesRead = in.read(buffer);\n\t\t\tif (bytesRead <= 0) {\n\t\t\t\tbreak;\n\t\t\t} else if (bytesRead <= bytesToCopy) {\n\t\t\t\tout.write(buffer, 0, bytesRead);\n\t\t\t\tbytesToCopy -= bytesRead;\n\t\t\t} else {\n\t\t\t\tout.write(buffer, 0, (int) bytesToCopy);\n\t\t\t\tbytesToCopy = 0;\n\t\t\t}\n\t\t}\n\t}\n","sourceCodeStart":4,"sourceCodeEnd":40,"githubUrl":"https://github.com/theonedev/onedev/blob/d44925c47c37992c828ea673a5f9620539bc3ff2/server-core/src/main/java/io/onedev/server/util/IOUtils.java#L4-L40","documentation":"IOUtils.copyRange copies a byte range from an input stream. It first skips range.getStart() bytes using skip(); if the stream ends (or misbehaves) before all required bytes are skipped, it throws IOException(\"Skipped only N bytes out of M required.\") because the requested range is beyond the available data.","triggerScenarios":"copyRange(in, range) where the underlying stream is shorter than range.getStart() bytes — e.g. requesting bytes 100-200 of a 50-byte resource. Also occurs when skip() silently stops early on certain stream implementations.","commonSituations":"HTTP Range requests against resources whose size changed (file truncated/overwritten between size check and read), cached Content-Length mismatch, or sparse reads at end-of-file.","solutions":["Verify the resource size before requesting the range; clamp range.getEnd() to size-1 or return 416 Range Not Satisfiable.","Re-read the resource to get a fresh, complete stream if it may have changed concurrently.","Check the source (file/blob) wasn't truncated — compare actual length to expected Content-Length.","Handle the IOException upstream by translating it into an HTTP 416 or an application-level out-of-range error."],"exampleFix":"// before\nIOUtils.copyRange(in, new ByteRange(1000, 2000)); // stream only has 50 bytes -> IOException\n// after\nlong size = getResourceSize();\nif (range.getEnd() < size) {\n  IOUtils.copyRange(in, range);\n} else {\n  throw newweb.exception... // respond 416 or serve full content\n}","handlingStrategy":"validation","validationCode":"long size = resource.getSize();\nif (range.getStart() >= size) {\n    throw new HttpRequestException(HttpStatus.CODE_REQUESTED_RANGE_NOT_SATISFIABLE, \"Range not satisfiable\");\n}","typeGuard":null,"tryCatchPattern":"try {\n    IOUtils.copyRange(in, range);\n} catch (IOException e) {\n    if (e.getMessage().startsWith(\"Skipped only\")) {\n        // translate to HTTP 416 Range Not Satisfiable\n    }\n}","preventionTips":["Always clamp ranges against the current resource size before copying.","Use a single consistent snapshot of the resource for size checks and reads.","Detect concurrent truncation via checksum/ETag checks."],"tags":["io","streams","range-request"],"backgroundTag":"value-out-of-range","analyzedSha":"d44925c47c37992c828ea673a5f9620539bc3ff2","analyzedAt":"2026-09-06T07:18:27.995Z","contentChangedAt":"2026-09-06T07:18:27.995Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}