alibaba/spring-ai-alibaba · error · NoSuchElementException

Checkpoint with id %s not found!

Error message

Checkpoint with id %s not found!

What it means

updateCheckpoint executes an UPDATE for the given thread and checkpoint id; if executeUpdate returns 0 rows affected, no row matched, the transaction is rolled back and a NoSuchElementException 'Checkpoint with id %s not found!' is thrown. This is a sentinel signaling the checkpoint you tried to update does not exist in the store.

Source

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

	protected void updateCheckpoint(String threadName, String checkpointId, Checkpoint checkpoint) throws Exception {
		Connection conn = null;

		try (Connection ignored = conn = dataSource.getConnection()) {
			conn.setAutoCommit(false);

			try (PreparedStatement preparedStatement = conn.prepareStatement(UPDATE_CHECKPOINT)) {
				String encodedState = encodeState(checkpoint.getState());
				preparedStatement.setString(1, checkpoint.getId());
				preparedStatement.setString(2, checkpoint.getNodeId());
				preparedStatement.setString(3, checkpoint.getNextNodeId());
				preparedStatement.setObject(4, encodedState, OracleType.JSON);
				preparedStatement.setString(5, stateSerializer.contentType());
				preparedStatement.setString(6, checkpointId);
				preparedStatement.setString(7, threadName);
				int rowsAffected = preparedStatement.executeUpdate();
				if (rowsAffected == 0) {
					conn.rollback();
					throw new NoSuchElementException(format("Checkpoint with id %s not found!", checkpointId));
				}
			}

			conn.commit();
			log.debug("Checkpoint with id {} for thread {} updated successfully.", checkpoint.getId(), threadName);
		}
		catch (SQLException | IOException ex) {
			log.error("Error updating checkpoint with id {} in thread {}", checkpoint.getId(), threadName, ex);
			rollback(conn, checkpoint, threadName);
			throw new Exception("Unable to update checkpoint", ex);
		}
	}

	@Override
	protected void deleteCheckpoints(String threadName, Collection<String> checkpointIds) throws Exception {
		if (checkpointIds.isEmpty()) {
			return;
		}

View on GitHub (pinned to f82da0b50f)

Solutions

  1. Confirm the checkpoint id and thread name are correct and that the checkpoint was inserted before the update
  2. Check whether retention (deleteCheckpoints) removed the checkpoint before the update; adjust history limits or ordering
  3. Insert the checkpoint first if it may not exist, or handle NoSuchElementException to fall back to insert
  4. Query the table (SELECT by thread/checkpoint id) to verify existence before updating

Example fix

// before: blind update, may throw NoSuchElementException
saver.updateCheckpoint(threadName, checkpointId, checkpoint);
// after: guard with existence check
if (saver.getTuple(threadName, checkpointId).isPresent()) {
    saver.updateCheckpoint(threadName, checkpointId, checkpoint);
} else {
    saver.put(threadName, checkpoint);
}
Defensive patterns

Strategy: validation

Validate before calling

// confirm the checkpoint exists (and is for this thread) before updating
Optional<Checkpoint> existing = saver.getTuple(threadName, checkpointId);
if (existing.isEmpty()) {
    // insert instead of update, or surface a clear 'checkpoint gone' condition
}

Try / catch

try {
    // update checkpoint
} catch (NoSuchElementException e) {
    // checkpoint missing (deleted by retention or wrong id): re-insert or re-derive
    log.warn("Checkpoint {} no longer stored; recreating", checkpointId);
    saver.put(threadName, checkpoint);
}

Prevention

When it happens

Trigger: Calling updateCheckpoint (directly or via a save/update path that assumes an existing checkpoint) with a checkpointId that was never inserted, was deleted by retention (deleteCheckpoints), or belongs to a different thread.

Common situations: Retention policies deleting old checkpoints that are then updated; passing a checkpoint id from a different thread; re-running from an in-memory checkpoint that was never persisted; race with a concurrent delete.

Understand the failure class

Background: Record Not Found Errors: "not found", RecordNotFound, and "was not found" — what they mean and how to fix them — this error's family across 28 libraries.

Related errors


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