alibaba/spring-ai-alibaba · error · Exception
Unable to insert checkpoint
Error message
Unable to insert checkpoint
What it means
insertCheckpoint wraps SQLException or IOException from the INSERT of a new checkpoint (and any connection/commit/rollback activity) into an Exception 'Unable to insert checkpoint'. The transaction is rolled back first via rollback(conn, threadId), so a failed insert leaves no partial row.
Source
Thrown at spring-ai-alibaba-graph-core/src/main/java/com/alibaba/cloud/ai/graph/checkpoint/savers/h2/H2Saver.java:379
protected void insertCheckpoint(String threadId, Checkpoint checkpoint) throws Exception {
Connection conn = null;
try (Connection ignored = conn = getConnection()) {
conn.setAutoCommit(false);
String persistedThreadId = activeThreadId(conn, threadId);
try (PreparedStatement ps = conn.prepareStatement(INSERT_CHECKPOINT)) {
ps.setString(1, checkpoint.getId());
ps.setString(2, persistedThreadId);
ps.setString(3, checkpoint.getNodeId());
ps.setString(4, checkpoint.getNextNodeId());
ps.setString(5, encodeState(checkpoint.getState()));
ps.setString(6, stateSerializer.contentType());
ps.executeUpdate();
}
conn.commit();
}
catch (SQLException | IOException ex) {
rollback(conn, threadId);
throw new Exception("Unable to insert checkpoint", ex);
}
}
private String activeThreadId(Connection conn, String threadName) throws SQLException {
Optional<String> activeThreadId = selectActiveThreadId(conn, threadName);
if (activeThreadId.isPresent()) {
return activeThreadId.get();
}
String persistedThreadId = UUID.randomUUID().toString();
try (PreparedStatement ps = conn.prepareStatement(INSERT_THREAD)) {
ps.setString(1, persistedThreadId);
ps.setString(2, threadName);
ps.executeUpdate();
return persistedThreadId;
}
catch (SQLException ex) {
if (isUniqueConstraintViolation(ex)) {View on GitHub (pinned to f82da0b50f)
Solutions
- Check the wrapped cause and verify the H2 database is reachable and the checkpoints table exists/has the expected columns.
- Initialize the schema before running (use the saver's DDL or an init migration).
- Ensure checkpoint state is serializable by the configured stateSerializer (all state values are supported types).
- Confirm the H2 file is not locked by another JVM/process and there is disk space.
Example fix
// before: table never created
H2DataSource.createScriptDataSource(...) then H2Saver directly
// after: init schema first
try (Connection c = dataSource.getConnection(); Statement st = c.createStatement()) {
st.execute(CHECKPOINTS_TABLE_DDL);
} Defensive patterns
Strategy: retry
Validate before calling
try (Connection c = dataSource.getConnection(); ResultSet rs = c.getMetaData().getTables(null, null, "CHECKPOINTS", null)) { if (!rs.next()) throw new IllegalStateException("checkpoints table missing — run schema init"); } Try / catch
try { saver.addCheckpoint(threadId, checkpoint); }
catch (Exception e) { if (isTransient(e.getCause())) retryWithBackoff(); else throw e; } Prevention
- Initialize the H2 schema at startup
- Ensure all graph state values are supported by stateSerializer
- Check disk space and exclusive file access for the H2 database
- Size the connection pool for checkpoint write load
When it happens
Trigger: Adding a checkpoint to a thread while: the H2 connection fails or the pool is exhausted, the checkpoints table does not exist or a column/constraint mismatches, the checkpoint state fails to serialize to the content type of stateSerializer (IOException), or the transaction commit fails.
Common situations: First run without the H2 table initialized; switching stateSerializer content type while reusing an old database; disk full or H2 file locked by another process; long graph run holding too many open connections.
Related errors
- Unable to load checkpoints
- Unable to load latest checkpoint
- Unable to load checkpoint
- Unable to update checkpoint
- Unable to delete retained checkpoints
AI-assisted analysis of alibaba/spring-ai-alibaba@f82da0b50f (2026-09-09).
Data as JSON: /api/errors/8d541b5ef7bf6a8c.
Report an issue: GitHub.