apache/dolphinscheduler · error · EmrServerlessTaskException

jobRunId is empty, cannot track application status

Error message

jobRunId is empty, cannot track application status

What it means

trackApplicationStatus requires a jobRunId to poll GetJobRun. It first tries the in-memory field, then falls back to appIds persisted for failover recovery. If both are empty, it throws EmrServerlessTaskException with this message, because the plugin cannot identify which job run to monitor.

Source

Thrown at dolphinscheduler-task-plugin/dolphinscheduler-task-emr-serverless/src/main/java/org/apache/dolphinscheduler/plugin/task/emrserverless/EmrServerlessTask.java:157

            log.info("Successfully submitted EMR Serverless job run, jobRunId: {}", jobRunId);

        } catch (EmrServerlessTaskException | SdkBaseException e) {
            log.error("EMR Serverless task submit failed", e);
            throw new TaskException("EMR Serverless task submit failed", e);
        }
    }

    @Override
    public void trackApplicationStatus() throws TaskException {
        try {
            // Recover jobRunId from appIds if needed (failover case)
            if (StringUtils.isEmpty(jobRunId) && StringUtils.isNotEmpty(getAppIds())) {
                jobRunId = getAppIds();
                log.info("Recovered EMR Serverless jobRunId from appIds: {}", jobRunId);
            }

            if (StringUtils.isEmpty(jobRunId)) {
                throw new EmrServerlessTaskException("jobRunId is empty, cannot track application status");
            }

            String currentState = getJobRunState();
            while (WAITING_STATES.contains(currentState)) {
                TimeUnit.SECONDS.sleep(10);
                currentState = getJobRunState();
            }

            final int exitCode = mapStateToExitCode(currentState);
            setExitStatusCode(exitCode);
            log.info("EMR Serverless job run [{}] finished with state: {}, exitCode: {}",
                    jobRunId, currentState, exitCode);

        } catch (EmrServerlessTaskException | SdkBaseException e) {
            log.error("EMR Serverless task tracking failed", e);
            setExitStatusCode(TaskConstants.EXIT_CODE_FAILURE);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();

View on GitHub (pinned to 02eac45a1b)

Solutions

  1. Ensure submitApplication completed and setAppIds(jobRunId) persisted appIds before tracking (check for earlier 'EMR Serverless task submit failed' errors)
  2. Re-run the task instance so a fresh jobRunId is submitted and stored
  3. If recovering manually, find the jobRunId in the AWS console/CloudTrail and set it as the task's appIds in the DB before retry
  4. Check the worker logs of the failed-over instance for the originally submitted jobRunId

Example fix

// before (worker died between submit and persist)
jobRunId = result.getJobRunId(); // process killed here -> appIds lost
// after
jobRunId = result.getJobRunId();
setAppIds(jobRunId); // must run immediately after submit; add log/state persist so failover can recover
Defensive patterns

Strategy: validation

Validate before calling

// before relying on tracking/failover recovery
String jobRunId = getAppIds();
if (StringUtils.isBlank(jobRunId)) {
    throw new IllegalStateException("appIds not persisted; cannot recover EMR Serverless jobRunId");
}

Type guard

boolean hasTrackableJob(EmrServerlessTask t) {
    return StringUtils.isNotEmpty(t.getAppIds());
}

Try / catch

try {
    task.trackApplicationStatus();
} catch (EmrServerlessTaskException e) {
    if (e.getMessage().contains("jobRunId is empty")) {
        log.error("No jobRunId persisted for failover; resubmit the task instance", e);
    }
    throw e;
}

Prevention

When it happens

Trigger: trackApplicationStatus is invoked without submitApplication having succeeded in this process and getAppIds() returns null/empty — typically after a worker failover where appIds was never persisted (submit crashed before setAppIds), or the task was defined so submitApplication is skipped.

Common situations: Worker crashed between StartJobRun success and setAppIds persistence; task instance retried on a different worker without stored appIds; DB row for appIds wiped or task configured to run track-only in custom code.

Understand the failure class

Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.

Related errors


AI-assisted analysis of apache/dolphinscheduler@02eac45a1b (2026-09-06). Data as JSON: /api/errors/01c52cfe8923f9f7. Report an issue: GitHub.