{"record":{"id":"3a37146750d94c09","repo":"apache/flink","slug":"savepointinfo-getfailurecause","errorCode":null,"errorMessage":"{savepointInfo.getFailureCause()}","messagePattern":"\\{savepointInfo\\.getFailureCause\\(\\)\\}","errorType":"exception","errorClass":"CompletionException","httpStatus":null,"severity":"error","filePath":"flink-clients/src/main/java/org/apache/flink/client/program/rest/RestClusterClient.java","lineNumber":688,"sourceCode":"            // we just return the savepoint trigger id in detached savepoint,\n            // that means the client could exit immediately\n            futureResult =\n                    responseFuture.thenApply((TriggerResponse tr) -> tr.getTriggerId().toString());\n        } else {\n            // otherwise we need to wait the savepoint to be succeeded\n            // and return the savepoint path\n            futureResult =\n                    responseFuture\n                            .thenCompose(\n                                    savepointTriggerResponseBody -> {\n                                        final TriggerId savepointTriggerId =\n                                                savepointTriggerResponseBody.getTriggerId();\n                                        return pollSavepointAsync(jobId, savepointTriggerId);\n                                    })\n                            .thenApply(\n                                    savepointInfo -> {\n                                        if (savepointInfo.getFailureCause() != null) {\n                                            throw new CompletionException(\n                                                    savepointInfo.getFailureCause());\n                                        }\n                                        return savepointInfo.getLocation();\n                                    });\n        }\n\n        return futureResult;\n    }\n\n    @Override\n    public CompletableFuture<Map<String, Object>> getAccumulators(JobID jobID, ClassLoader loader) {\n        final JobAccumulatorsHeaders accumulatorsHeaders = JobAccumulatorsHeaders.getInstance();\n        final JobAccumulatorsMessageParameters accMsgParams =\n                accumulatorsHeaders.getUnresolvedMessageParameters();\n        accMsgParams.jobPathParameter.resolve(jobID);\n        accMsgParams.includeSerializedAccumulatorsParameter.resolve(\n                Collections.singletonList(true));\n","sourceCodeStart":670,"sourceCodeEnd":706,"githubUrl":"https://github.com/apache/flink/blob/2f3c205e9266cb30240eb7f4fdab15cad629a70f/flink-clients/src/main/java/org/apache/flink/client/program/rest/RestClusterClient.java#L670-L706","documentation":"Thrown when a savepoint operation completes but the JobManager reports a non-null failure cause in the SavepointInfo response. After triggering a savepoint via REST and polling its status, if the savepoint failed on the server side (e.g., target directory not writable, job cancelled before savepoint completed), the stored Throwable is rethrown.","triggerScenarios":"Calling triggerSavepoint or stopWithSavepoint when the savepoint cannot complete: the savepoint directory does not exist or is not writable; the job is cancelled or fails before the savepoint finishes; the state backend encounters an error during snapshot.","commonSituations":"Savepoint target directory (state.savepoints.dir) is misconfigured or points to an inaccessible HDFS/S3 path; job finishes or is cancelled concurrently with the savepoint trigger; storage quota exceeded.","solutions":["Read the savepointInfo.getFailureCause() message for the exact server-side error.","Verify the savepoint directory exists and is writable by the JobManager process.","If the job was cancelled concurrently, retry the savepoint on a running job.","For S3/HDFS targets, confirm credentials and permissions in the cluster configuration."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n    String savepointPath = client.triggerSavepoint(jobId, savepointDir, false, formatType, false).get();\n} catch (ExecutionException e) {\n    Throwable cause = ExceptionUtils.stripExecutionException(e);\n    // cause is savepointInfo.getFailureCause() — the server-side savepoint error\n    log.error(\"Savepoint failed: {}\", cause.getMessage());\n}","preventionTips":["Pre-create and verify the savepoint target directory.","Ensure S3/HDFS credentials and permissions are configured on the cluster.","Do not cancel the job concurrently with a savepoint trigger."],"tags":["savepoint","rest-client","async-operation"],"backgroundTag":null,"analyzedSha":"2f3c205e9266cb30240eb7f4fdab15cad629a70f","analyzedAt":"2026-08-14T08:48:24.518Z","schemaVersion":2},"datasetVersion":"2026-08-14T10:17:34.591Z"}