flowable/flowable-engine · error · FlowableException

Job failed

Error message

Job {jobId} failed

What it means

Wrapper error thrown by CmmnManagementServiceImpl.executeJob when executing ExecuteJobCmd throws a RuntimeException that is NOT a FlowableException. Flowable rethrows its own exceptions as-is but wraps unexpected ones (NPE, ClassCastException, etc.) into a generic FlowableException with cause preserved.

Solutions

  1. Inspect the cause via e.getCause() — the real bug is in the wrapped exception's stack trace
  2. Fix the underlying job handler/delegate that threw the runtime exception
  3. Verify serialized job data compatibility after Flowable upgrades
  4. Catch FlowableException at the caller and log cause chain for diagnosis

Example fix

// before
} catch (RuntimeException e) {
    log.error("job failed", e); // message says 'Job x failed' with no detail
}
// after
} catch (FlowableException e) {
    Throwable cause = e.getCause();
    log.error("root cause of job failure", cause);
}
Defensive patterns

Strategy: try-catch

Try / catch

try { managementService.executeJob(jobId); } catch (FlowableException e) { Throwable root = e.getCause(); if (root != null) log.error("job {} root cause", jobId, root); }

Prevention

When it happens

Trigger: executeJob(jobId) where the job execution fails with a non-Flowable RuntimeException — e.g. NullPointerException inside a job handler, a scripting/serialization bug, or classpath issues in the job's delegate code.

Common situations: Buggy service task/delegate code throwing NPE; incompatible serialized variable payloads after an upgrade; missing class in the runtime classpath when the job handler loads it.

Related errors


AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11). Data as JSON: /api/errors/64e473b9012bebc7. Report an issue: GitHub.

Appendix: source

Thrown at modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/CmmnManagementServiceImpl.java:118

    @Override
    public Collection<String> getTableNames() {
        return commandExecutor.execute(new GetTableNamesCmd());
    }
    
    @Override
    public void executeJob(String jobId) {
        if (jobId == null) {
            throw new FlowableIllegalArgumentException("Job id is null");
        }

        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 void deleteHistoryJob(String jobId) {
        commandExecutor.execute(new DeleteHistoryJobCmd(jobId, configuration.getJobServiceConfiguration()));
    }

View on GitHub (pinned to d6d39ce1c6)