{"record":{"id":"7c2a7303f78368a0","repo":"hibernate/hibernate-orm","slug":"length-must-be-greater-than-or-equal-to-zero","errorCode":null,"errorMessage":"Length must be greater than or equal to zero","messagePattern":"Length must be greater than or equal to zero","errorType":"exception","errorClass":"SQLException","httpStatus":null,"severity":"error","filePath":"hibernate-core/src/main/java/org/hibernate/engine/jdbc/proxy/ClobProxy.java","lineNumber":153,"sourceCode":"\t\tfinal long endIndex = Math.min( start + length - 1, string.length() );\n\t\treturn string.substring( (int) start - 1, (int) endIndex );\n\t}\n\n\t@Override\n\tpublic Reader getCharacterStream(long start, long length) throws SQLException {\n\t\tif ( start < 1 ) {\n\t\t\tthrow new SQLException( \"Start position 1-based; must be 1 or more.\" );\n\t\t}\n\t\tif ( start > length() + 1 ) {\n\t\t\tthrow new SQLException( \"Start position [\" + start + \"] cannot exceed overall CLOB length [\" + length() + \"]\" );\n\t\t}\n\t\tif ( length > Integer.MAX_VALUE ) {\n\t\t\tthrow new SQLException( \"Can't deal with Clobs larger than 'Integer.MAX_VALUE'\" );\n\t\t}\n\t\tif ( length < 0 ) {\n\t\t\t// javadoc for getCharacterStream(long,int) specifies that the start+length must not exceed the\n\t\t\t// total length (this is at odds with the behavior of getSubString(long,int))\n\t\t\tthrow new SQLException( \"Length must be greater than or equal to zero\" );\n\t\t}\n\t\treturn DataHelper.subStream( getCharacterStream(), start-1, (int) length );\n\t}\n\n\t@Override\n\tpublic void free() throws SQLException {\n\t\tcharacterStream.release();\n\t}\n\n\tprotected void resetIfNeeded() {\n\t\ttry {\n\t\t\tif ( needsReset ) {\n\t\t\t\tcharacterStream.asReader().reset();\n\t\t\t}\n\t\t}\n\t\tcatch ( IOException ioe ) {\n\t\t\tthrow new HibernateException( \"could not reset reader\", ioe );\n\t\t}","sourceCodeStart":135,"sourceCodeEnd":171,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-core/src/main/java/org/hibernate/engine/jdbc/proxy/ClobProxy.java#L135-L171","documentation":"In ClobProxy.getCharacterStream(long start, long length) a negative length is rejected with this SQLException (message variant without the period, distinct from the getSubString message). The source comment notes the JDBC javadoc requires start+length to stay within the Clob, so a negative length is a caller bug caught before the sub-stream is created. The check is unreachable for values above Integer.MAX_VALUE, which the preceding check already rejected.","triggerScenarios":"Calling clob.getCharacterStream(1, -1); a remaining-chars computation (total - consumed) going negative after the content is exhausted; forwarding a -1 'unlimited' sentinel from configuration.","commonSituations":"Windowed streaming loops that underflow at the end of the content; optional size parameters defaulting to -1; tests probing invalid arguments.","solutions":["Pass length >= 0 (0 is legal, yielding an empty reader)","Clamp remaining counts: long len = Math.max(0L, remaining)","Translate 'unlimited' sentinels to the true remaining length before the call"],"exampleFix":"// before\nReader r = clob.getCharacterStream(1, remaining); // remaining < 0\n\n// after\nlong len = Math.max(0L, remaining);\nif (len > 0) { Reader r = clob.getCharacterStream(1, len); }","handlingStrategy":"validation","validationCode":"static Reader safeReader(java.sql.Clob clob, long start, long length) throws SQLException {\n    if (start < 1) throw new IllegalArgumentException(\"start must be >= 1\");\n    long len = Math.max(0L, length);                // negative length means 'nothing'\n    return clob.getCharacterStream(start, len);\n}","typeGuard":null,"tryCatchPattern":"try {\n    r = clob.getCharacterStream(start, length);\n} catch (SQLException e) {\n    if (e.getMessage() != null && e.getMessage().contains(\"greater than or equal to zero\")) {\n        r = clob.getCharacterStream(start, 0);      // degrade to empty reader\n    } else {\n        throw e;\n    }\n}","preventionTips":["Floor all remaining-character computations at zero","Resolve 'unlimited' configuration sentinels to the true remaining count before the call","Note this message has no trailing period - match text carefully when catching"],"tags":["hibernate","jdbc","clob","lob","negative-length","argument-validation","sql-exception"],"backgroundTag":"jdbc-lob-negative-length","analyzedSha":"fad1729dce015f908198d57a8d80274a30f905a5","analyzedAt":"2026-08-22T04:13:57.527Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}