flowable/flowable-engine · error · FlowableException
Job ${jobId} failed
Error message
Job ${jobId} failed What it means
ManagementService.executeJob(String) wraps job execution (ExecuteJobCmd) and, when a non-Flowable RuntimeException escapes the command, rethrows it as a FlowableException with message "Job <jobId> failed" and the original as cause. FlowableExceptions themselves are rethrown unchanged. This normalizes unexpected runtime failures (NPE, IllegalStateException, etc.) during job execution.
Source
Thrown at modules/flowable-engine/src/main/java/org/flowable/engine/impl/ManagementServiceImpl.java:153
public String getTableName(Class<?> entityClass, boolean includePrefix) {
return commandExecutor.execute(new GetTableNameCmd(entityClass, includePrefix));
}
@Override
public TableMetaData getTableMetaData(String tableName) {
return commandExecutor.execute(new GetTableMetaDataCmd(tableName, configuration.getEngineCfgKey()));
}
@Override
public void executeJob(String jobId) {
try {
commandExecutor.execute(new ExecuteJobCmd(jobId, configuration.getJobServiceConfiguration()));
} catch (RuntimeException e) {
if (e instanceof FlowableException) {
throw e;
} else {
throw new FlowableException("Job " + jobId + " failed", e);
}
}
}
@Override
public void executeHistoryJob(String historyJobId) {
commandExecutor.execute(new ExecuteHistoryJobCmd(historyJobId, configuration.getJobServiceConfiguration()));
}
@Override
public String getHistoryJobHistoryJson(String historyJobId) {
return commandExecutor.execute(new GetHistoryJobAdvancedConfigurationCmd(historyJobId, configuration.getJobServiceConfiguration()));
}
@Override
public Job moveTimerToExecutableJob(String jobId) {
return commandExecutor.execute(new MoveTimerToExecutableJobCmd(jobId, configuration.getJobServiceConfiguration()));
}View on GitHub (pinned to d6d39ce1c6)
Solutions
- Inspect the cause via e.getCause() — the real failure is the wrapped exception
- Fix the underlying job delegate/handler that threw the RuntimeException
- Redeploy the job's associated definition/classes so resolution succeeds
- Check the Flowable job log/exception stack for the original failure point
Example fix
// before
managementService.executeJob(jobId);
// after
try {
managementService.executeJob(jobId);
} catch (FlowableException e) {
Throwable cause = e.getCause();
LOG.error("Job failed: {}", cause != null ? cause.getMessage() : e.getMessage(), cause != null ? cause : e);
} Defensive patterns
Strategy: try-catch
Validate before calling
// verify the job exists and inspect its last failure before re-executing
Job job = managementService.createJobQuery().jobId(jobId).singleResult();
if (job == null || job.getExceptionMessage() != null) {
LOG.warn("Job {} previously failed: {}", jobId, job != null ? job.getExceptionMessage() : "not found");
} Try / catch
try {
managementService.executeJob(jobId);
} catch (FlowableException e) {
Throwable root = e.getCause() != null ? e.getCause() : e;
LOG.error("Job " + jobId + " failed due to " + root.getClass().getSimpleName(), root);
} Prevention
- Always inspect getCause() — the "Job X failed" message wraps the real RuntimeException
- Keep delegate classes stable across deployments or ensure the same classes are on the classpath when re-running old jobs
- Log and monitor job exceptionMessage via JobQuery to fix root causes before manual re-execution
When it happens
Trigger: Calling managementService.executeJob(jobId) where the job's handler throws a non-Flowable RuntimeException — e.g. a NullPointerException in a service task, class-cast errors in a delegate, or a broken job configuration.
Common situations: Manually re-executing a dead-letter/async job whose delegate class changed between deployments; jobs touching missing beans or classes causing RuntimeExceptions inside the command.
Related errors
- Could not find a job with id '${jobId}'.
- ${e.getMessage()}
- Error while propagating error-event for " + execution
- Error retrieving idm engine info
- ${historyJobEntity} failed
AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11).
Data as JSON: /api/errors/2e841d1ececc7c61.
Report an issue: GitHub.