{"record":{"id":"1a29727f6d70b6e0","repo":"hibernate/hibernate-orm","slug":"start-position-1-based-must-be-1-or-more-1a2972","errorCode":null,"errorMessage":"Start position 1-based; must be 1 or more.","messagePattern":"Start position 1-based; must be 1 or more\\.","errorType":"exception","errorClass":"SQLException","httpStatus":null,"severity":"error","filePath":"hibernate-core/src/main/java/org/hibernate/engine/jdbc/proxy/ClobProxy.java","lineNumber":126,"sourceCode":"\t@Override\n\tpublic OutputStream setAsciiStream(long pos) {\n\t\tthrow notSupported();\n\t}\n\n\t@Override\n\tpublic Writer setCharacterStream(long pos) {\n\t\tthrow notSupported();\n\t}\n\n\t@Override\n\tpublic void truncate(long len) throws SQLException {\n\t\tthrow notSupported();\n\t}\n\n\t@Override\n\tpublic String getSubString(long start, int 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 < 0 ) {\n\t\t\tthrow new SQLException( \"Length must be great-than-or-equal to zero.\" );\n\t\t}\n\t\tfinal String string = characterStream.asString();\n\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 ) {","sourceCodeStart":108,"sourceCodeEnd":144,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-core/src/main/java/org/hibernate/engine/jdbc/proxy/ClobProxy.java#L108-L144","documentation":"Hibernate's ClobProxy implements java.sql.Clob for non-contextual creation (e.g. Hibernate.getLobHelper().createClob(String) or createClob(Reader, long)). Its getSubString(long start, int length) validates start against the JDBC contract, which is 1-based: position 1 is the first character. Passing 0 or a negative value throws this SQLException before any substring is built.","triggerScenarios":"Calling clob.getSubString(0, n) on a Hibernate-created Clob; translating String.substring(i, j) calls directly into getSubString(i, j - i) without shifting the origin; using a 0-based loop counter as the start.","commonSituations":"Developers mapping String.substring (0-based) semantics onto Clob.getSubString (1-based); text-windowing code (previews, excerpts) written against arrays; test data helpers assuming array indexing.","solutions":["Pass start >= 1, i.e. use index + 1 for 0-based offsets","When porting s.substring(a, b), call getSubString(a + 1, b - a)","Pin the contract with a test: getSubString(1, 1) must return the first character"],"exampleFix":"// before (String.substring semantics)\nString head = clob.getSubString(0, 10); // throws\n\n// after (JDBC 1-based)\nString head = clob.getSubString(1, 10);","handlingStrategy":"validation","validationCode":"static String substring0(java.sql.Clob clob, int beginIndex, int endIndex) throws SQLException {\n    long start = beginIndex + 1;                    // String is 0-based, Clob is 1-based\n    int length = Math.max(0, endIndex - beginIndex);\n    return clob.getSubString(start, length);\n}","typeGuard":null,"tryCatchPattern":"try {\n    s = clob.getSubString(start, length);\n} catch (SQLException e) {\n    if (e.getMessage() != null && e.getMessage().contains(\"Start position\")) {\n        s = clob.getSubString(beginIndex + 1, length); // fix origin, retry\n    } else {\n        throw e;\n    }\n}","preventionTips":["Port String.substring(a, b) as getSubString(a + 1, b - a), never verbatim","Wrap Clob text access in one helper that owns the 0-to-1-based shift","Add a regression test reading the first character at position 1"],"tags":["hibernate","jdbc","clob","lob","off-by-one","indexing","sql-exception"],"backgroundTag":"jdbc-lob-position-validation","analyzedSha":"fad1729dce015f908198d57a8d80274a30f905a5","analyzedAt":"2026-08-22T04:13:57.527Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}