{"record":{"id":"d0b4d09eacf028d8","repo":"apache/seatunnel","slug":"checkpoint-restore-requires-a-terminal-source-job","errorCode":null,"errorMessage":"checkpoint restore requires a terminal source job, restoreSourceJobId=%s, current source job status=%s","messagePattern":"checkpoint restore requires a terminal source job, restoreSourceJobId=(.+?), current source job status=(.+?)","errorType":"exception","errorClass":"JobException","httpStatus":null,"severity":"error","filePath":"seatunnel-engine/seatunnel-engine-server/src/main/java/org/apache/seatunnel/engine/server/CheckpointRestoreValidator.java","lineNumber":56,"sourceCode":"        }\n\n        Long restoreSourceJobId = jobImmutableInformation.getRestoreSourceJobId();\n        if (restoreSourceJobId == null) {\n            throw new JobException(\n                    \"restoreSourceJobId is required when restoreMode=\"\n                            + jobImmutableInformation.getRestoreMode());\n        }\n        if (restoreSourceJobId == destinationJobId) {\n            throw new JobException(\n                    \"restoreSourceJobId must reference a historical terminal source job when restoreMode=CHECKPOINT\");\n        }\n\n        JobStatus sourceJobStatus =\n                activeSourceJobStatusResolver == null\n                        ? null\n                        : activeSourceJobStatusResolver.apply(restoreSourceJobId);\n        if (sourceJobStatus != null && !sourceJobStatus.isEndState()) {\n            throw new JobException(\n                    String.format(\n                            \"checkpoint restore requires a terminal source job, restoreSourceJobId=%s, current source job status=%s\",\n                            restoreSourceJobId, sourceJobStatus));\n        }\n    }\n}\n","sourceCodeStart":38,"sourceCodeEnd":63,"githubUrl":"https://github.com/apache/seatunnel/blob/cf67b549a7a6c35fa0beb12d83c62892427ea919/seatunnel-engine/seatunnel-engine-server/src/main/java/org/apache/seatunnel/engine/server/CheckpointRestoreValidator.java#L38-L63","documentation":"When restoreMode=CHECKPOINT and a status resolver is available for the restore source job, the source job must be in an end state (finished/failed/canceled) because its final checkpoint data is what gets restored. If the source job is still running (or in a non-terminal state), validation throws this JobException.","triggerScenarios":"validate() resolves activeSourceJobStatusResolver.apply(restoreSourceJobId) and the returned JobStatus.isEndState() is false (e.g. RUNNING, CREATED) while submitting a CHECKPOINT-mode restore.","commonSituations":"Attempting to restore from a source job that is still running; racing automation that submits the restore before the source job finished; querying the wrong job id (an active unrelated job).","solutions":["Wait until the source job reaches a terminal state (FINISHED/FAILED/CANCELED) before submitting the restore.","Verify restoreSourceJobId points at the completed job whose checkpoints you want.","Check the source job's status via REST API / seatunnel.sh client before resubmitting.","Fix automation to trigger restore only after source-job completion event."],"exampleFix":"// before: restore while source still running\nsubmitRestore(883745192014848L); // status = RUNNING\n// after: poll until terminal state\nwhile (!status(jobId).isEndState()) Thread.sleep(5000);\nsubmitRestore(883745192014848L);","handlingStrategy":"validation","validationCode":"JobStatus s = getJobStatus(restoreSourceJobId); // via REST or client\nif (s != null && !s.isEndState()) {\n  throw new IllegalStateException(\"Wait for source job to finish before restoring: \" + s);\n}","typeGuard":null,"tryCatchPattern":"try {\n  client.submitJob(request);\n} catch (JobException e) {\n  if (e.getMessage().startsWith(\"checkpoint restore requires a terminal source job\")) {\n    // poll source status, resubmit after it ends\n  }\n}","preventionTips":["Trigger restores from source-job completion events, not timers","Poll job status until isEndState before submitting a restore","Confirm the restore source id maps to the intended historical job"],"tags":["checkpoint-restore","job-status","invalid-state","zeta-engine"],"backgroundTag":"invalid-state-transition","analyzedSha":"cf67b549a7a6c35fa0beb12d83c62892427ea919","analyzedAt":"2026-09-10T21:44:55.265Z","contentChangedAt":"2026-09-10T21:44:55.265Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}