apache/seatunnel · critical · SeaTunnelEngineException

${jobResult.error}

Error message

${jobResult.error}

What it means

After waiting for the job to finish via clientJobProxy.waitForJobCompleteV2(), ClientExecuteCommand throws a SeaTunnelEngineException carrying jobResult.getError() when the engine reported an error or the final JobStatus is FAILED. The message shown to the user is the engine-side error text (the literal '${jobResult.error}' in the catalog means the message is dynamic). It surfaces the root failure of the executed pipeline to the CLI caller.

Solutions

  1. Read the error text returned in the exception — it contains the engine-side root cause — and fix the underlying connector/config problem.
  2. Check the Zeta master/worker logs for the full stack trace of the failing task.
  3. Validate the config with --dry-run before resubmitting to catch connectivity/static issues early.
  4. Retry the job after fixing; if transient (network, resource), resubmit once resources are available.
Defensive patterns

Strategy: try-catch

Validate before calling

// before submitting: validate config and connectivity
// seatunnel.sh --config job.conf --dry-run CONNECT

Try / catch

try { client.execute(); } catch (SeaTunnelEngineException e) { log.error("Job failed on engine: {}", e.getMessage()); alertOps(e.getMessage()); }

Prevention

When it happens

Trigger: A submitted job completes with status FAILED, or waitForJobCompleteV2 returns a JobResult whose error field is non-empty — e.g. a connector threw during reading/writing, a task failed and the job failed over and gave up, or checkpointing timed out.

Common situations: Bad connector config causing runtime failures; sink unable to connect to the target database; data-quality errors in transforms; engine worker crashes; resource exhaustion on the cluster.

Related errors


AI-assisted analysis of apache/seatunnel@cf67b549a7 (2026-09-10). Data as JSON: /api/errors/9a03fca0f8619a03. Report an issue: GitHub.

Appendix: source

Thrown at seatunnel-core/seatunnel-starter/src/main/java/org/apache/seatunnel/core/starter/seatunnel/command/ClientExecuteCommand.java:283

                executorService.scheduleAtFixedRate(
                        jobMetricsRunner,
                        0,
                        seaTunnelConfig.getEngineConfig().getPrintJobMetricsInfoInterval(),
                        TimeUnit.SECONDS);

                if (!isLocalMode) {
                    // LOCAL mode does not require running the job status runner
                    executorService.schedule(
                            new JobStatusRunner(engineClient.getJobClient(), jobId),
                            0,
                            TimeUnit.SECONDS);
                }
                // wait for job complete
                JobResult jobResult = clientJobProxy.waitForJobCompleteV2();
                jobStatus = jobResult.getStatus();
                if (StringUtils.isNotEmpty(jobResult.getError())
                        || jobResult.getStatus().equals(JobStatus.FAILED)) {
                    throw new SeaTunnelEngineException(jobResult.getError());
                }
                // get job end time
                endTime = LocalDateTime.now();
                // get job statistic information when job finished
                jobMetricsSummary = engineClient.getJobMetricsSummary(jobId);
            }
        } catch (Exception e) {
            throw new CommandExecuteException("SeaTunnel job executed failed", e);
        } finally {
            if (jobMetricsSummary != null) {
                // print job statistics information when job finished
                log.info(
                        StringFormatUtils.formatTable(
                                "Job Statistic Information",
                                "Start Time",
                                DateTimeUtils.toString(
                                        startTime, DateTimeUtils.Formatter.YYYY_MM_DD_HH_MM_SS),
                                "End Time",

View on GitHub (pinned to cf67b549a7)