alibaba/spring-ai-alibaba · error · Exception

Unable to release checkpoint

Error message

Unable to release checkpoint

What it means

releaseThread wraps SQLException raised while executing the release-thread transaction (prepare/execute RELEASE_THREAD or commit) into Exception 'Unable to release checkpoint'. The transaction is rolled back first via rollback(conn, threadId), leaving the thread state unchanged. Note the message says 'checkpoint' although the operation releases a thread.

Source

Thrown at spring-ai-alibaba-graph-core/src/main/java/com/alibaba/cloud/ai/graph/checkpoint/savers/h2/H2Saver.java:484

	@Override
	protected void releaseThread(String threadId) throws Exception {
		Connection conn = null;
		try (Connection ignored = conn = getConnection()) {
			conn.setAutoCommit(false);
			try (PreparedStatement ps = conn.prepareStatement(RELEASE_THREAD)) {
				ps.setString(1, threadId);
				int rowsAffected = ps.executeUpdate();
				if (rowsAffected == 0) {
					conn.rollback();
					throw new IllegalStateException(format("Thread '%s' not found or already released", threadId));
				}
			}
			conn.commit();
		}
		catch (SQLException ex) {
			rollback(conn, threadId);
			throw new Exception("Unable to release checkpoint", ex);
		}
	}

	protected Connection getConnection() throws SQLException {
		return dataSource.getConnection();
	}

	private void rollback(Connection conn, String threadId) {
		if (conn == null) {
			return;
		}
		try {
			conn.rollback();
		}
		catch (SQLException ex) {
			log.error("Failed to rollback transaction for thread {}", threadId, ex);
		}
	}

View on GitHub (pinned to f82da0b50f)

Solutions

  1. Check the wrapped cause for the exact SQL error (connection closed, table missing).
  2. Ensure the connection pool/dataSource is still open when release runs (order shutdown hooks: release threads before closing the pool).
  3. Re-align the table schema with the current H2Saver version.
  4. Retry the release; the rollback keeps state consistent.

Example fix

// before: pool closed before threads released
dataSource.close();
releaseThread(threadId); // SQLException -> Unable to release checkpoint
// after: release first, then close
releaseThread(threadId);
dataSource.close();
Defensive patterns

Strategy: try-catch

Validate before calling

if (dataSource instanceof AutoCloseable ds && closed) throw new IllegalStateException("release threads before closing the DataSource");

Try / catch

try { releaseThread(threadId); }
catch (Exception e) { log.error("thread release failed: {}", e.getCause() != null ? e.getCause().getMessage() : e.getMessage()); }

Prevention

When it happens

Trigger: Releasing a thread when: the H2 connection fails or is closed, the thread/checkpoints table is missing or the RELEASE_THREAD SQL no longer matches the schema, or the commit fails on a lock conflict.

Common situations: App shutdown while the connection pool is already closed; schema drift after upgrading the library; H2 server mode connection dropped mid-operation.

Related errors


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