flowable/flowable-engine · error · FlowableException
Could not find job for id
Error message
Could not find job for id ${jobId} What it means
UnacquireExternalWorkerJobCmd.execute throws this FlowableException (not a typed not-found exception) when findById on the external worker job entity manager returns null for the given jobId. The job to unacquire no longer exists in the runtime tables, so the release operation cannot be performed.
Solutions
- Treat this as a benign race in the handler: catch FlowableException and log/skip if the job is gone
- Refresh the job id from a fresh ExternalWorkerJobQuery before unacquiring
- Reduce lock expiration races by handling jobs well within the lock duration
- Verify the datasource points at the same database the job was acquired from
Example fix
// before
externalWorkerJobService.unacquireExternalWorkerJob(jobId, workerId); // throws if job vanished
// after
try {
externalWorkerJobService.unacquireExternalWorkerJob(jobId, workerId);
} catch (FlowableException e) {
if (e.getMessage() != null && e.getMessage().contains("Could not find job")) {
logger.info("Job {} already gone; skipping unacquire", jobId);
} else {
throw e;
}
} Defensive patterns
Strategy: try-catch
Validate before calling
ExternalWorkerJobEntity job = externalWorkerJobService.createExternalWorkerJobQuery().jobId(jobId).singleResult();
if (job == null) { /* job gone, skip */ } Try / catch
try {
externalWorkerJobService.unacquireExternalWorkerJob(jobId, workerId);
} catch (FlowableException e) {
logger.info("Job {} disappeared before unacquire (already completed?)", jobId);
} Prevention
- Design handlers to treat missing jobs as benign races
- Keep processing within the lock duration to avoid re-acquisition
- Avoid caching job ids across process restarts
- Verify datasource consistency between acquire and unacquire environments
When it happens
Trigger: Calling unacquireExternalWorkerJob with an id of a job that was completed, deleted, or never an external worker job; the job lock expired and another worker completed/removed it; stale id retained after the async executor processed the job; wrong datasource/environment.
Common situations: Two workers racing on the same expired lock; job ids cached across restarts; pointing the client at a different database (dev vs prod); job moved out of the external worker table after acquisition.
Understand the failure class
Background: "Not found" and "does not exist" errors: why "Task not found", "No such folder", and "Can't find" fire when a lookup comes back empty — this error's family across 14 libraries.
Related errors
- Could not find a job with id
- No External Worker job found for id
- No external worker job found with id '
- Active execution could not be found with activity id
- at least one of userId or groups must be provided
AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11).
Data as JSON: /api/errors/f0bcb0d70eb6ab00.
Report an issue: GitHub.
Appendix: source
Thrown at modules/flowable-job-service/src/main/java/org/flowable/job/service/impl/cmd/UnacquireExternalWorkerJobCmd.java:50
this.workerId = workerId;
this.jobServiceConfiguration = jobServiceConfiguration;
}
@Override
public Void execute(CommandContext commandContext) {
if (StringUtils.isEmpty(jobId)) {
throw new FlowableIllegalArgumentException("job id must not be empty");
}
if (StringUtils.isEmpty(workerId)) {
throw new FlowableIllegalArgumentException("worker id must not be empty");
}
ExternalWorkerJobEntityManager externalWorkerJobEntityManager = jobServiceConfiguration.getExternalWorkerJobEntityManager();
ExternalWorkerJobEntity jobEntity = externalWorkerJobEntityManager.findById(jobId);
if (jobEntity == null) {
throw new FlowableException("Could not find job for id " + jobId);
}
if (!jobEntity.getLockOwner().equals(workerId)) {
throw new FlowableException(jobEntity + " is locked with a different worker id");
}
jobEntity.setLockExpirationTime(null);
jobEntity.setLockOwner(null);
externalWorkerJobEntityManager.update(jobEntity);
if (jobEntity.isExclusive()) {
new UnlockExclusiveJobCmd(jobEntity, jobServiceConfiguration).execute(commandContext);
}
return null;
}
}
View on GitHub (pinned to d6d39ce1c6)