hibernate/hibernate-orm · error · SQLException
Start position 1-based; must be 1 or more.
Error message
Start position 1-based; must be 1 or more.
What it means
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.
Source
Thrown at hibernate-core/src/main/java/org/hibernate/engine/jdbc/proxy/ClobProxy.java:126
@Override
public OutputStream setAsciiStream(long pos) {
throw notSupported();
}
@Override
public Writer setCharacterStream(long pos) {
throw notSupported();
}
@Override
public void truncate(long len) throws SQLException {
throw notSupported();
}
@Override
public String getSubString(long start, int length) throws SQLException {
if ( start < 1 ) {
throw new SQLException( "Start position 1-based; must be 1 or more." );
}
if ( start > length() + 1 ) {
throw new SQLException( "Start position [" + start + "] cannot exceed overall CLOB length [" + length() + "]" );
}
if ( length < 0 ) {
throw new SQLException( "Length must be great-than-or-equal to zero." );
}
final String string = characterStream.asString();
final long endIndex = Math.min( start + length - 1, string.length() );
return string.substring( (int) start - 1, (int) endIndex );
}
@Override
public Reader getCharacterStream(long start, long length) throws SQLException {
if ( start < 1 ) {
throw new SQLException( "Start position 1-based; must be 1 or more." );
}
if ( start > length() + 1 ) {View on GitHub (pinned to fad1729dce)
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
Example fix
// before (String.substring semantics) String head = clob.getSubString(0, 10); // throws // after (JDBC 1-based) String head = clob.getSubString(1, 10);
Defensive patterns
Strategy: validation
Validate before calling
static String substring0(java.sql.Clob clob, int beginIndex, int endIndex) throws SQLException {
long start = beginIndex + 1; // String is 0-based, Clob is 1-based
int length = Math.max(0, endIndex - beginIndex);
return clob.getSubString(start, length);
} Try / catch
try {
s = clob.getSubString(start, length);
} catch (SQLException e) {
if (e.getMessage() != null && e.getMessage().contains("Start position")) {
s = clob.getSubString(beginIndex + 1, length); // fix origin, retry
} else {
throw e;
}
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- Start position 1-based; must be 1 or more.
- Start position [${start}] cannot exceed overall CLOB length
- Start position [<start>] cannot exceed overall CLOB length [
- Length must be great-than-or-equal to zero.
- Can't deal with Clobs larger than 'Integer.MAX_VALUE'
AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22).
Data as JSON: /api/errors/1a29727f6d70b6e0.
Report an issue: GitHub.