apache/flink · error · ProgramInvocationException
Job failed
Error message
Job failed
What it means
Thrown by ClusterClientJobClientAdapter.getJobExecutionResult when jobResult.toJobExecutionResult(classLoader) throws a Throwable. The JobResult object carries the serialized exception (if any) from the job's failure, and toJobExecutionResult re-throws it during deserialization. This wraps the original failure cause in a ProgramInvocationException with message 'Job failed'. This is the user-facing signal that the job did not complete successfully when using the JobClient API.
Source
Thrown at flink-clients/src/main/java/org/apache/flink/client/deployment/ClusterClientJobClientAdapter.java:129
clusterClientProvider,
(clusterClient -> clusterClient.getAccumulators(jobID, classLoader)));
}
@Override
public CompletableFuture<JobExecutionResult> getJobExecutionResult() {
checkNotNull(classLoader);
return bridgeClientRequest(
clusterClientProvider,
(clusterClient ->
clusterClient
.requestJobResult(jobID)
.thenApply(
(jobResult) -> {
try {
return jobResult.toJobExecutionResult(classLoader);
} catch (Throwable t) {
throw new CompletionException(
new ProgramInvocationException(
"Job failed", jobID, t));
}
})));
}
@Override
public CompletableFuture<CoordinationResponse> sendCoordinationRequest(
String operatorUid, CoordinationRequest request) {
return bridgeClientRequest(
clusterClientProvider,
clusterClient ->
clusterClient.sendCoordinationRequest(jobID, operatorUid, request));
}
@Override
public void reportHeartbeat(long expiredTimestamp) {
bridgeClientRequest(View on GitHub (pinned to 2f3c205e92)
Solutions
- Inspect the root cause in the ProgramInvocationException to identify the actual job failure reason
- Check the JobManager logs and the Flink Web UI for the ArchivedExecutionGraph exception
- Fix the underlying job logic or resource issue, then resubmit
- Use jobClient.getJobStatus() to poll before calling getJobExecutionResult() if you want to handle failures gracefully
Example fix
// before
JobExecutionResult result = jobClient.getJobExecutionResult().get();
// after
try {
JobExecutionResult result = jobClient.getJobExecutionResult().get();
} catch (ExecutionException e) {
if (e.getCause() instanceof ProgramInvocationException) {
Throwable jobFailure = e.getCause().getCause();
LOG.error("Job failed with cause:", jobFailure);
}
throw e;
} Defensive patterns
Strategy: try-catch
Try / catch
try {
JobExecutionResult result = jobClient.getJobExecutionResult().get();
} catch (ExecutionException e) {
Throwable cause = e.getCause();
if (cause instanceof ProgramInvocationException) {
Throwable jobFailure = cause.getCause();
LOG.error("Job failed due to: {}", jobFailure.getMessage(), jobFailure);
}
} Prevention
- Check jobClient.getJobStatus() before calling getJobExecutionResult() to detect FAILED early
- Inspect ArchivedExecutionGraph in the Flink Web UI for root cause
- Handle the ProgramInvocationException cause chain to surface the real error to users
When it happens
Trigger: The submitted job finished in a FAILED state due to a runtime exception in user code, a serialization error, or an operator crash. When the JobClient's getJobExecutionResult() future completes, it attempts to materialize the result and encounters the stored exception from the ArchivedExecutionGraph.
Common situations: User code throws an unhandled exception inside a ProcessFunction/MapFunction; OutOfMemoryError during job execution; checkpoint failure that triggers job failure; source/sink connector timeout or connection refused.
AI-assisted analysis of apache/flink@2f3c205e92 (2026-08-14).
Data as JSON: /api/errors/222b25be1e172a74.
Report an issue: GitHub.