apache/flink · error · IllegalArgumentException

JobStatus {jobStatus} does not have a corresponding Applicat

Error message

JobStatus {jobStatus} does not have a corresponding ApplicationState.

What it means

Thrown by ApplicationState.fromJobStatus when the given JobStatus is not one of the globally terminal states mapped to an ApplicationState (FINISHED, CANCELED, FAILED). The framework maps only terminal job outcomes to application lifecycle states; non-terminal states (CREATED, RUNNING, RESTARTING, FAILING, CANCELLING, RECONCILING, SUSPENDED, INITIALIZING) and UNKNOWN have no ApplicationState equivalent, so the call is a programming error.

Source

Thrown at flink-core/src/main/java/org/apache/flink/api/common/ApplicationState.java:84

    private static final Map<JobStatus, ApplicationState> JOB_STATUS_APPLICATION_STATE_MAP =
            new HashMap<>();

    static {
        // only globally terminal JobStatus can have a corresponding ApplicationState
        JOB_STATUS_APPLICATION_STATE_MAP.put(JobStatus.FAILED, ApplicationState.FAILED);
        JOB_STATUS_APPLICATION_STATE_MAP.put(JobStatus.CANCELED, ApplicationState.CANCELED);
        JOB_STATUS_APPLICATION_STATE_MAP.put(JobStatus.FINISHED, ApplicationState.FINISHED);
    }

    /**
     * Derives the ApplicationState that corresponds to the given JobStatus. This method only
     * accepts globally terminal JobStatus. If the job status is not globally terminal, this method
     * throws an IllegalArgumentException.
     */
    public static ApplicationState fromJobStatus(JobStatus jobStatus) {
        if (!JOB_STATUS_APPLICATION_STATE_MAP.containsKey(jobStatus)) {
            throw new IllegalArgumentException(
                    "JobStatus " + jobStatus + " does not have a corresponding ApplicationState.");
        }

        return JOB_STATUS_APPLICATION_STATE_MAP.get(jobStatus);
    }
}

View on GitHub (pinned to 2f3c205e92)

Solutions

  1. Check jobStatus.isGloballyTerminalState() before calling fromJobStatus, and skip/await otherwise.
  2. Restrict upstream logic to only the three terminal states the map supports.
  3. If you need to handle non-terminal states, branch on them explicitly rather than routing through fromJobStatus.

Example fix

// before
ApplicationState s = ApplicationState.fromJobStatus(jobStatus);
// after
if (!jobStatus.isGloballyTerminalState()) {
    // job still running; do not derive an ApplicationState yet
    return;
}
ApplicationState s = ApplicationState.fromJobStatus(jobStatus);
Defensive patterns

Strategy: validation

Validate before calling

if (jobStatus == null || !jobStatus.isGloballyTerminalState()) {
    // not convertible; await or skip
    return;
}
ApplicationState s = ApplicationState.fromJobStatus(jobStatus);

Type guard

public static boolean isConvertible(JobStatus js) {
    return js != null && js.isGloballyTerminalState();
}

Prevention

When it happens

Trigger: Calling ApplicationState.fromJobStatus with a still-running or non-terminal JobStatus; polling a job and feeding its current status into fromJobStatus without checking isGloballyTerminalState() first.

Common situations: Application-mode deployments that translate JobStatus to ApplicationState for cluster shutdown logic; code that assumed every JobStatus maps cleanly; tests passing arbitrary enum values.

Related errors


AI-assisted analysis of apache/flink@2f3c205e92 (2026-08-14). Data as JSON: /api/errors/fdc3fc0cd562ed77. Report an issue: GitHub.