alibaba/spring-ai-alibaba · error · Exception

Unable to insert checkpoint

Error message

Unable to insert checkpoint

What it means

PostgresSaver.insertCheckpoint wraps SQLException or IOException raised while persisting a checkpoint (including its rollback handling) into Exception('Unable to insert checkpoint'). The transaction is rolled back first, so the checkpoint is not saved and graph state persistence for that step fails.

Source

Thrown at spring-ai-alibaba-graph-core/src/main/java/com/alibaba/cloud/ai/graph/checkpoint/savers/postgresql/PostgresSaver.java:464

		}
		catch (SQLException | IOException | ClassNotFoundException ex) {
			throw new Exception("Unable to load checkpoint", ex);
		}
	}

	@Override
	protected void insertCheckpoint(String threadId, Checkpoint checkpoint) throws Exception {
		Connection conn = null;
		try (Connection ignored = conn = getConnection()) {
			conn.setAutoCommit(false);
			insertCheckpoint(conn, threadId, checkpoint);
			conn.commit();
			log.debug("Checkpoint {} for thread {} inserted successfully.", checkpoint.getId(), threadId);
		}
		catch (SQLException | IOException ex) {
			log.error("Error inserting checkpoint with id {} in thread {}", checkpoint.getId(), threadId, ex);
			rollback(conn, checkpoint, threadId);
			throw new Exception("Unable to insert checkpoint", ex);
		}
	}

	private void insertCheckpoint(Connection conn, String threadId, Checkpoint checkpoint) throws Exception {
		UUID threadUUID = null;

		// 1. Upsert thread information
		try (PreparedStatement ps = conn.prepareStatement(UPSERT_THREAD)) {
			var field = 0;
			ps.setObject(++field, UUID.randomUUID(), Types.OTHER);
			ps.setString(++field, threadId);
			ps.setString(++field, threadId);

			log.trace("Executing upsert thread:\n---\n{}---", UPSERT_THREAD);

			try (ResultSet rs = ps.executeQuery()) {
				if (rs.next()) {
					threadUUID = rs.getObject("thread_id", UUID.class);

View on GitHub (pinned to f82da0b50f)

Solutions

  1. Inspect the wrapped cause: IOException -> check that all state values are serializable by the configured StateSerializer; SQLException -> check connectivity, schema, and constraints.
  2. Ensure the checkpoint tables exist and match the current library version's schema.
  3. Verify connection pool sizing and timeouts (HikariCP) to avoid transient connection failures.
  4. Enable idempotent retries at a higher level since the transaction was rolled back.

Example fix

// before
state.value("conn", new Connection(...)); // non-serializable object in state
// after
state.value("conn", new ConnectionInfo(host, port)); // store serializable data only
Defensive patterns

Strategy: try-catch

Validate before calling

// Java: check serializability of state values before saving
for (var entry : state.values().entrySet()) {
    if (!(entry.getValue() instanceof Serializable)) {
        throw new IllegalStateException("Non-serializable state value: " + entry.getKey());
    }
}

Try / catch

try {
    saver.save(config, checkpoint);
} catch (Exception e) {
    if ("Unable to insert checkpoint".equals(e.getMessage())) {
        // rolled back; inspect cause: fix serialization or retry on healthy connection
    }
}

Prevention

When it happens

Trigger: Saving a checkpoint when the INSERT fails: connection loss/timeout, constraint violations, table missing, or IOException while serializing the checkpoint state (e.g. non-serializable object in state).

Common situations: Putting non-Serializable objects into graph state with a JDK-based serializer; Postgres connection pool exhaustion; checkpoint table missing or columns changed after upgrade; statement timeout under load.

Related errors


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