apache/shardingsphere · error · IllegalStateException
Failed to read java.sql.Clob
Error message
Failed to read java.sql.Clob
What it means
Thrown while serializing a java.sql.Clob parameter for the Firebird wire protocol: reading the Clob (length(), getSubString()) raised SQLException. The proxy converts the Clob to bytes using the connection charset and registers it as a BLOB; any JDBC failure during that read is wrapped in IllegalStateException with the cause attached.
Source
Thrown at database/protocol/dialect/firebird/src/main/java/org/apache/shardingsphere/database/protocol/firebird/packet/command/query/statement/execute/protocol/FirebirdBlobBinaryProtocolValue.java:116
blobId = (Long) value;
} else if (value instanceof byte[]) {
blobId = register(payload.getConnectionId(), (byte[]) value);
} else if (value instanceof Blob) {
try {
blobId = register(payload.getConnectionId(), readAllBytes(((Blob) value).getBinaryStream()));
} catch (final SQLException ex) {
throw new IllegalStateException("Failed to read java.sql.Blob stream", ex);
} catch (final IOException ex) {
throw new IllegalStateException("Failed to read java.sql.Blob content", ex);
}
} else if (value instanceof Clob) {
try {
Clob clob = (Clob) value;
int len = (int) Math.min(Integer.MAX_VALUE, clob.length());
String str = clob.getSubString(1L, len);
blobId = register(payload.getConnectionId(), str.getBytes(payload.getCharset()));
} catch (final SQLException ex) {
throw new IllegalStateException("Failed to read java.sql.Clob", ex);
}
} else {
blobId = register(payload.getConnectionId(), value.toString().getBytes(payload.getCharset()));
}
payload.writeInt8(blobId);
}
@Override
public int getLength(final FirebirdPacketPayload payload) {
return 8;
}
}
View on GitHub (pinned to e952770a21)
Solutions
- Read the chained SQLException to confirm the lifetime/validity problem
- Create, bind, and execute the Clob within one open connection and transaction
- Bind String or byte[] instead of java.sql.Clob when the content is in memory
- Verify the connection charset can encode the Clob content; encode explicitly with setBytes() if charset behavior is unclear
Example fix
// before: Clob used after its connection/transaction ended ps.setClob(1, staleClob); // after: bind the string directly on a live connection ps.setString(1, text);
Defensive patterns
Strategy: validation
Validate before calling
// verify the Clob is servicable on this connection before binding
private static boolean isClobUsable(final Clob clob, final Connection conn) {
try {
return !conn.isClosed() && clob.length() >= 0;
} catch (SQLException ex) {
return false;
}
}
// if (!isClobUsable(clob, conn)) ps.setString(1, reloadedText); Try / catch
try {
ps.setClob(1, clob);
} catch (IllegalStateException ex) {
if (ex.getCause() instanceof SQLException) {
ps.setString(1, readClobAgainFromSource()); // fall back to String binding
} else {
throw ex;
}
} Prevention
- Bind String instead of Clob when the text is in memory
- Keep the Clob's transaction open until binding finishes; avoid reusing Clobs across connections
When it happens
Trigger: Binding a java.sql.Clob parameter where clob.length() or clob.getSubString(1, len) throws — the Clob's owning connection is closed, the Clob was freed, or the driver cannot serve it in the current transaction state.
Common situations: Clobs carried across connection boundaries; free() called before execute; drivers that invalidate temp Clobs on commit (similar lifetime issues as Blob, plus charset conversion via payload.getCharset()).
Related errors
- Failed to read java.sql.Blob stream
- Failed to read java.sql.Blob content
- Unexpected trailing bytes in BLR
- BLOB fields are not supported in Firebird batch operations
- Expected blr_short NULL indicator, got: %s
AI-assisted analysis of apache/shardingsphere@e952770a21 (2026-08-14).
Data as JSON: /api/errors/0f3f61aea0ae5d9a.
Report an issue: GitHub.