alibaba/spring-ai-alibaba · error · Exception

Unable to delete retained checkpoints

Error message

Unable to delete retained checkpoints

What it means

deleteCheckpoints removes the checkpoints not retained (older history beyond the configured limit) using a prepared DELETE with an IN clause. A SQLException during this cleanup is wrapped in an Exception with message 'Unable to delete retained checkpoints'.

Source

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

	}

	@Override
	protected void deleteCheckpoints(String threadName, Collection<String> checkpointIds) throws Exception {
		if (checkpointIds.isEmpty()) {
			return;
		}
		try (Connection connection = dataSource.getConnection();
				PreparedStatement preparedStatement = connection.prepareStatement(
						DELETE_CHECKPOINTS.formatted(String.join(", ", Collections.nCopies(checkpointIds.size(), "?"))))) {
			int index = 1;
			for (String checkpointId : checkpointIds) {
				preparedStatement.setString(index++, checkpointId);
			}
			preparedStatement.setString(index, threadName);
			preparedStatement.executeUpdate();
		}
		catch (SQLException ex) {
			throw new Exception("Unable to delete retained checkpoints", ex);
		}
	}

	@Override
	protected void releaseThread(String threadName) throws Exception {
		Connection conn = null;

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

			try (PreparedStatement preparedStatement = conn.prepareStatement(RELEASE_THREAD)) {
				preparedStatement.setString(1, threadName);
				int rowsAffected = preparedStatement.executeUpdate();

				if (rowsAffected == 0) {
					conn.rollback();
					throw new IllegalStateException(
							format("Thread '%s' not found or already released", threadName));

View on GitHub (pinned to f82da0b50f)

Solutions

  1. Check the wrapped SQLException cause for the exact Oracle error code
  2. Grant DELETE privileges on the checkpoint table to the configured user
  3. Verify the table exists and matches the saver's expected schema
  4. Retry the save operation if the failure was a transient connection issue
Defensive patterns

Strategy: validation

Validate before calling

// verify DELETE privilege before relying on retention trimming
try (Connection c = dataSource.getConnection()) {
    DatabaseMetaData md = c.getMetaData();
    try (ResultSet rs = md.getTablePrivileges(null, null, "CKP_CHECKPOINTS")) {
        boolean canDelete = false;
        while (rs.next()) if ("DELETE".equals(rs.getString("PRIVILEGE"))) canDelete = true;
        if (!canDelete) log.warn("DB user may lack DELETE privilege; retention cleanup will fail");
    }
}

Try / catch

try {
    // save checkpoint (triggers retention delete)
} catch (Exception e) {
    log.error("Retention cleanup failed: {}", e.getCause(), e);
    // decide whether new checkpoint save can proceed despite failed trim
}

Prevention

When it happens

Trigger: Saving a new checkpoint triggers history trimming; the DELETE fails due to connectivity, permissions (no DELETE privilege), table missing, or an oversized IN list / SQL error.

Common situations: Database user granted only INSERT/SELECT; network interruption during save; very large checkpoint-id lists producing SQL errors; table recreated concurrently by another instance.

Related errors


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