apache/seatunnel · error · SeaTunnelEngineException
Job is trying to leave terminal state ${current}
Error message
Job is trying to leave terminal state ${current} What it means
SeaTunnel Zeta engine throws this when a job state transition attempts to move a PhysicalPlan out of a terminal state (FINISHED, FAILED, CANCELED, etc.). Terminal states are final by design; the plan guards the transition inside updateJobState so that no stale callback or late state update can resurrect a finished job. It is a SeaTunnelEngineException, so it usually surfaces during coordinator operations like cancel or savepoint racing with job completion.
Source
Thrown at seatunnel-engine/seatunnel-engine-server/src/main/java/org/apache/seatunnel/engine/server/dag/physical/PhysicalPlan.java:334
log.warn(
"{} current state is null, skip transition to {}",
jobFullName,
targetState);
return;
}
log.debug(
"Try to update the {} state from {} to {}", jobFullName, current, targetState);
if (current.equals(targetState)) {
log.info(
"{} current state equals target state: {}, skip", jobFullName, targetState);
return;
}
// consistency check
if (current.isEndState()) {
String message = "Job is trying to leave terminal state " + current;
throw new SeaTunnelEngineException(message);
}
// Now do the actual state transition, we must update runningJobStateTimestampsIMap
// first and then can update runningJobStateIMap
updateStateInfo(current, targetState);
reportJobStateEvent(targetState);
stateProcess();
} catch (Exception e) {
log.error(ExceptionUtils.getMessage(e));
if (!targetState.equals(JobStatus.FAILING)) {
makeJobFailing(e);
}
}
}
public JobImmutableInformation getJobImmutableInformation() {
return jobImmutableInformation;View on GitHub (pinned to cf67b549a7)
Solutions
- Check the job's current state via REST/CLI before issuing cancel, savepoint, or stop operations
- Treat the exception as confirmation that the job already completed; query the final JobResult instead of retrying the transition
- Fix client code to subscribe to job state events rather than polling and issuing duplicate lifecycle calls
- If it occurs during cluster restart/failover replay, verify the runningJobStateIMap is consistent and no duplicated callbacks are registered
Example fix
// before
if (jobMetrics.someCondition()) {
jobClient.savepoint(); // may race with completion
}
// after
JobStatus s = jobClient.getJobStatus();
if (!s.isEndState()) {
jobClient.savepoint();
} Defensive patterns
Strategy: try-catch
Validate before calling
JobStatus s = jobClient.getJobStatus(jobId);
if (s.isEndState()) { /* skip cancel/savepoint/stop */ } Type guard
boolean isTerminal(JobStatus s) { return s.isEndState(); } Try / catch
try { jobClient.cancelJob(jobId); } catch (SeaTunnelEngineException e) { if (e.getMessage().contains("leave terminal state")) { /* job already finished; treat as no-op */ } else { throw e; } } Prevention
- Query job state before lifecycle operations
- Subscribe to job state events instead of blind re-submission
- Avoid issuing savepoint/cancel concurrently with expected completion
When it happens
Trigger: Calling cancelJob/savepointJob/stopJob after the job already reached an end state; a pipeline-end callback firing after the plan was marked terminal; startJob on a plan whose state was already finalized by a prior run; concurrent state updates landing after terminal transition.
Common situations: User issues a cancel at the same moment the job finishes; retry/restart logic re-invokes startJob on an already-terminal plan; savepoint requested on a completed job; race between master node failover replay and job completion events.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- Unknown Job State: ${jobStatus}
- get job state error
- schema-change-after checkpoint is already completed, job id:
- ${taskFullName} reset state failed, only end state can be re
- The state must be end state from ExecutionService, can not b
AI-assisted analysis of apache/seatunnel@cf67b549a7 (2026-09-10).
Data as JSON: /api/errors/7365c43efbc329d1.
Report an issue: GitHub.