alibaba/spring-ai-alibaba · error · Exception

Unable to load latest checkpoint

Error message

Unable to load latest checkpoint

What it means

MysqlSaver.selectLatestCheckpoint() wraps SQLException, IOException, or ClassNotFoundException from querying/deserializing the most recent checkpoint of a thread into an Exception with this message. It is thrown when resuming a graph and the latest checkpoint row cannot be read or decoded. An empty result is NOT an error — Optional.empty() is returned.

Source

Thrown at spring-ai-alibaba-graph-core/src/main/java/com/alibaba/cloud/ai/graph/checkpoint/savers/mysql/MysqlSaver.java:454

		}
		return checkpoints;
	}

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

			preparedStatement.setString(1, threadName);
			try (ResultSet resultSet = preparedStatement.executeQuery()) {
				if (resultSet.next()) {
					return Optional.of(readCheckpoint(resultSet));
				}
				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 {
		try (Connection connection = dataSource.getConnection();
				PreparedStatement preparedStatement = connection.prepareStatement(SELECT_CHECKPOINT_BY_ID)) {

			preparedStatement.setString(1, threadName);
			preparedStatement.setString(2, checkpointId);
			try (ResultSet resultSet = preparedStatement.executeQuery()) {
				if (resultSet.next()) {
					return Optional.of(readCheckpoint(resultSet));
				}
				return Optional.empty();
			}
		}
		catch (SQLException | IOException | ClassNotFoundException ex) {

View on GitHub (pinned to f82da0b50f)

Solutions

  1. Check the root cause (ex.getCause()) to identify whether it is connectivity, corruption, or a missing class.
  2. Confirm DB connectivity and that the checkpoints table schema matches the current library version.
  3. Align serializer/class versions: redeploy the app with the classes that wrote the checkpoint, or migrate the data.
  4. Clear the corrupted checkpoint rows so the run can start fresh.

Example fix

// before
Runnable runnable = graph.compile(checkpointSaver);
runnable.invoke(inputs, config); // fails with 'Unable to load latest checkpoint'
// after
try {
    runnable.invoke(inputs, config);
} catch (Exception e) {
    if (e.getCause() instanceof ClassNotFoundException cnfe) {
        log.error("State class missing: {}", cnfe.getMessage());
    }
    // start fresh run without resume
}
Defensive patterns

Strategy: fallback

Validate before calling

boolean dbUp;
try (Connection c = dataSource.getConnection()) { dbUp = c.isValid(2); }

Try / catch

try {
    runnable.invoke(inputs, resumeConfig);
} catch (Exception e) {
    log.warn("resume failed ({}), starting fresh", e.getCause().toString());
    runnable.invoke(inputs, freshConfig);
}

Prevention

When it happens

Trigger: Resuming a thread (e.g. via stateGraph compiled runnable resume from a checkpointer) when the SELECT of the latest checkpoint fails at the JDBC level, the blob is corrupt, or a serialized class is absent from the classpath.

Common situations: MySQL outage or failover mid-run; checkpoint written by a different version of the library with an incompatible serialization format; custom state classes removed after a refactor; shared checkpoint DB across environments.

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/b60b15dbc70dead9. Report an issue: GitHub.