alibaba/spring-ai-alibaba · error · Exception

Unable to load latest checkpoint

Error message

Unable to load latest checkpoint

What it means

selectLatestCheckpoint queries Oracle for the most recent checkpoint of a thread and deserializes it with readCheckpoint. Any SQLException, IOException, or ClassNotFoundException during that work is wrapped in an Exception with message 'Unable to load latest checkpoint'. An empty result set is not an error; only query/deserialization failures are thrown.

Source

Thrown at spring-ai-alibaba-graph-core/src/main/java/com/alibaba/cloud/ai/graph/checkpoint/savers/oracle/OracleSaver.java:418

	}

	@Override
	protected Optional<Checkpoint> selectLatestCheckpoint(String threadName) throws Exception {
		ObjectMapper objectMapper = osonObjectMapper();
		try (Connection connection = dataSource.getConnection();
				PreparedStatement preparedStatement = connection.prepareStatement(SELECT_LATEST_CHECKPOINT)) {

			defineCheckpointColumns(preparedStatement);
			preparedStatement.setString(1, threadName);
			try (ResultSet resultSet = preparedStatement.executeQuery()) {
				if (resultSet.next()) {
					return Optional.of(readCheckpoint(resultSet, objectMapper));
				}
				return Optional.empty();
			}
		}
		catch (SQLException | IOException | ClassNotFoundException ex) {
			throw new Exception("Unable to load latest checkpoint", ex);
		}
	}

	@Override
	protected Optional<Checkpoint> selectCheckpointById(String threadName, String checkpointId) throws Exception {
		ObjectMapper objectMapper = osonObjectMapper();
		try (Connection connection = dataSource.getConnection();
				PreparedStatement preparedStatement = connection.prepareStatement(SELECT_CHECKPOINT_BY_ID)) {

			defineCheckpointColumns(preparedStatement);
			preparedStatement.setString(1, threadName);
			preparedStatement.setString(2, checkpointId);
			try (ResultSet resultSet = preparedStatement.executeQuery()) {
				if (resultSet.next()) {
					return Optional.of(readCheckpoint(resultSet, objectMapper));
				}
				return Optional.empty();
			}

View on GitHub (pinned to f82da0b50f)

Solutions

  1. Check the wrapped cause to distinguish SQL failure vs deserialization failure
  2. Verify table existence, connectivity, and credentials; test the SELECT manually
  3. Clean or migrate unreadable rows (e.g. after class/package renames) so the latest checkpoint can deserialize
  4. Rebuild thread state by re-running the workflow if the latest checkpoint is unrecoverable
Defensive patterns

Strategy: try-catch

Validate before calling

// verify connectivity and that the thread has at least one checkpoint before resuming
try (Connection c = dataSource.getConnection();
     PreparedStatement ps = c.prepareStatement("SELECT COUNT(*) FROM CKP_CHECKPOINTS WHERE THREAD_NAME = ?")) {
    ps.setString(1, threadName);
    try (ResultSet rs = ps.executeQuery()) { rs.next(); return rs.getInt(1) > 0; }
} catch (SQLException e) { throw new IllegalStateException("DB not ready", e); }

Try / catch

try {
    // resume using latest checkpoint
} catch (Exception e) {
    log.error("Could not load latest checkpoint: {}", e.getCause(), e);
    // fallback: start the thread from scratch if resume is not critical
}

Prevention

When it happens

Trigger: Resuming a graph/thread state (e.g. via checkpoint loading on session resume) when the latest-checkpoint SELECT fails due to connectivity, missing table, or the stored row cannot be decoded (unknown class, corrupt payload).

Common situations: Database outage or failover during agent run; table schema drift after upgrade; state classes renamed so ClassNotFoundException occurs while reading; bad credentials.

Understand the failure class

Background: Database query failed: Internal Server Error 500s wrapping SQL, Prisma, and connection failures — what to check first — this error's family across 16 libraries.

Related errors


AI-assisted analysis of alibaba/spring-ai-alibaba@f82da0b50f (2026-09-09). Data as JSON: /api/errors/930247f6834d74b6. Report an issue: GitHub.