{"record":{"id":"f4152828552e569a","repo":"hibernate/hibernate-orm","slug":"unable-to-skip-needed-bytes","errorCode":null,"errorMessage":"Unable to skip needed bytes","messagePattern":"Unable to skip needed bytes","errorType":"exception","errorClass":"HibernateException","httpStatus":null,"severity":"error","filePath":"hibernate-core/src/main/java/org/hibernate/type/descriptor/java/DataHelper.java","lineNumber":103,"sourceCode":"\n\t/**\n\t * Extracts a portion of the contents of the given reader/stream as a string.\n\t *\n\t * @param characterStream The reader for the content\n\t * @param start The start position/offset (0-based, per general stream/reader contracts).\n\t * @param length The amount to extract\n\t *\n\t * @return The content as string\n\t */\n\tprivate static String extractString(Reader characterStream, long start, int length) {\n\t\tif ( length == 0 ) {\n\t\t\treturn \"\";\n\t\t}\n\t\tfinal var stringBuilder = new StringBuilder( length );\n\t\ttry {\n\t\t\tfinal long skipped = characterStream.skip( start );\n\t\t\tif ( skipped != start ) {\n\t\t\t\tthrow new HibernateException( \"Unable to skip needed bytes\" );\n\t\t\t}\n\t\t\tfinal int bufferSize = getSuggestedBufferSize( length );\n\t\t\tfinal char[] buffer = new char[bufferSize];\n\t\t\tint charsRead = 0;\n\t\t\twhile ( true ) {\n\t\t\t\tfinal int amountRead = characterStream.read( buffer, 0, bufferSize );\n\t\t\t\tif ( amountRead == -1 ) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tstringBuilder.append( buffer, 0, amountRead );\n\t\t\t\tif ( amountRead < bufferSize ) {\n\t\t\t\t\t// we have read up to the end of stream\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcharsRead += amountRead;\n\t\t\t\tif ( charsRead >= length ) {\n\t\t\t\t\tbreak;\n\t\t\t\t}","sourceCodeStart":85,"sourceCodeEnd":121,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/DataHelper.java#L85-L121","documentation":"In the substring variant extractString(Reader characterStream, long start, int length), Hibernate first positions the stream with characterStream.skip(start); if the reader reports skipping fewer characters than requested, it throws HibernateException('Unable to skip needed bytes') before reading anything. It fires when the LOB reader cannot seek — usually because the stream is shorter than start or the driver's skip() is not fully conformant.","triggerScenarios":"Partial CLOB extraction (the start/length paths) where the character stream ends before start; a driver Reader whose skip() legitimately returns less than n; start offsets computed from stale length metadata.","commonSituations":"Concurrent truncation of the row's LOB between length computation and read; locator-based LOBs on drivers with weak skip support; offsets derived from a previous read of the row.","solutions":["Validate offsets against Clob.length() before extraction and clamp start to the actual length","Upgrade the JDBC driver — skip() conformance bugs are a known driver issue","Avoid partial reads: read the whole CLOB and substring in Java via Clob.getSubString","Re-read the row in a fresh transaction if the LOB can change concurrently"],"exampleFix":"// before\nReader r = clob.getCharacterStream();\nString part = extractBySkip(r, 500, 100); // may fail: skipped != 500\n\n// after\nString all = clob.getSubString(1, (int) clob.length());\nString part = all.substring(500, Math.min(600, all.length()));","handlingStrategy":"validation","validationCode":"long len = clob.length();\nif (start < 0 || start >= len) {\n    throw new IllegalArgumentException(\"start \" + start + \" outside LOB length \" + len);\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always bound start/length by Clob.length() before extraction","Prefer full reads plus in-memory substring over stream skipping","Pin a recent JDBC driver — skip() conformance varies"],"tags":["hibernate","lob","clob","skip","stream"],"backgroundTag":"lob-stream-skip-failed","analyzedSha":"fad1729dce015f908198d57a8d80274a30f905a5","analyzedAt":"2026-08-22T04:13:57.527Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}