{"record":{"id":"78107f0ef2ddd5b4","repo":"alibaba/spring-ai-alibaba","slug":"unable-to-update-checkpoint-78107f","errorCode":null,"errorMessage":"Unable to update checkpoint","messagePattern":"Unable to update checkpoint","errorType":"exception","errorClass":"Exception","httpStatus":null,"severity":"error","filePath":"spring-ai-alibaba-graph-core/src/main/java/com/alibaba/cloud/ai/graph/checkpoint/savers/postgresql/PostgresSaver.java","lineNumber":550,"sourceCode":"\t\t\t\tps.setString(++field, stateSerializer.contentType());\n\t\t\t\tps.setString(++field, threadId);\n\t\t\t\tps.setObject(++field, UUID.fromString(checkpointId), Types.OTHER);\n\t\t\t\tlog.trace(\"Executing update checkpoint:\\n---\\n{}---\", UPDATE_CHECKPOINT);\n\t\t\t\tint rowsAffected = ps.executeUpdate();\n\t\t\t\tif (rowsAffected == 0) {\n\t\t\t\t\tconn.rollback();\n\t\t\t\t\tthrow new NoSuchElementException(format(\"Checkpoint with id %s not found!\", checkpointId));\n\t\t\t\t}\n\t\t\t}\n\t\t\tconn.commit();\n\t\t\tlog.debug(\"Checkpoint with id {} for thread {} updated successfully.\",\n\t\t\t\t\tcheckpoint.getId(),\n\t\t\t\t\tthreadId);\n\t\t}\n\t\tcatch (SQLException | IOException ex) {\n\t\t\tlog.error(\"Error updating checkpoint with id {} in thread {}\", checkpoint.getId(), threadId, ex);\n\t\t\trollback(conn, checkpoint, threadId);\n\t\t\tthrow new Exception(\"Unable to update checkpoint\", ex);\n\t\t}\n\t}\n\n\t@Override\n\tprotected void deleteCheckpoints(String threadId, Collection<String> checkpointIds) throws Exception {\n\t\tif (checkpointIds.isEmpty()) {\n\t\t\treturn;\n\t\t}\n\t\ttry (Connection conn = getConnection();\n\t\t\t\tPreparedStatement ps = conn.prepareStatement(\n\t\t\t\t\t\tDELETE_CHECKPOINTS.formatted(String.join(\", \", Collections.nCopies(checkpointIds.size(), \"?\"))))) {\n\t\t\tps.setString(1, threadId);\n\t\t\tint index = 2;\n\t\t\tfor (String checkpointId : checkpointIds) {\n\t\t\t\tps.setObject(index++, UUID.fromString(checkpointId), Types.OTHER);\n\t\t\t}\n\t\t\tps.executeUpdate();\n\t\t}","sourceCodeStart":532,"sourceCodeEnd":568,"githubUrl":"https://github.com/alibaba/spring-ai-alibaba/blob/f82da0b50f35744c13968191be2b1cd2452ef550/spring-ai-alibaba-graph-core/src/main/java/com/alibaba/cloud/ai/graph/checkpoint/savers/postgresql/PostgresSaver.java#L532-L568","documentation":"PostgresSaver.updateCheckpoint wraps SQLException or IOException raised during the checkpoint UPDATE (after performing rollback) into Exception('Unable to update checkpoint'). The transaction is rolled back so the row keeps its previous content. Distinct from the NoSuchElementException case: here the SQL or serialization itself failed.","triggerScenarios":"Updating an existing checkpoint when the UPDATE fails (connection loss, constraint/lock timeout, schema mismatch) or serializing the new checkpoint state throws IOException (non-serializable state content).","commonSituations":"Row locks held by long transactions; non-serializable objects added to state between insert and update; DB failover mid-transaction; column type changes after upgrade.","solutions":["Inspect the cause: IOException -> fix serialization of the state; SQLException -> check connectivity, locks, and schema.","Ensure all values in the checkpoint state are serializable by the configured StateSerializer.","Check for blocking transactions/locks on the checkpoints table (pg_locks) if timeouts occur.","Retry the update; the rollback guarantees a consistent prior state."],"exampleFix":"// before\nstate.value(\"payload\", new FileInputStream(file)); // non-serializable\n// after\nstate.value(\"payload\", Files.readAllBytes(Path.of(file))); // serializable byte[]","handlingStrategy":"retry","validationCode":"// Java: ensure new state values remain serializable before update\nstate.values().values().forEach(v -> {\n    if (v != null && !(v instanceof Serializable)) {\n        throw new IllegalStateException(\"Cannot serialize: \" + v.getClass());\n    }\n});","typeGuard":null,"tryCatchPattern":"try {\n    saver.replaceCheckpoint(threadId, checkpointId, checkpoint);\n} catch (Exception e) {\n    if (\"Unable to update checkpoint\".equals(e.getMessage()) && isTransient(e.getCause())) {\n        // safe to retry: transaction was rolled back\n        retryUpdate();\n    }\n}","preventionTips":["Keep checkpoint state serializable throughout the graph lifecycle.","Watch pg_locks for contention on the checkpoints table.","Use retry policies for transient connection errors.","Keep the schema aligned with the library version."],"tags":["postgres","checkpoint","update","serialization","transaction"],"backgroundTag":"database-write-failed","analyzedSha":"f82da0b50f35744c13968191be2b1cd2452ef550","analyzedAt":"2026-09-09T15:32:42.421Z","contentChangedAt":"2026-09-09T15:32:42.421Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}