flowable/flowable-engine · error · FlowableObjectNotFoundException
Could not find a job with id ''.
Error message
Could not find a job with id ''.
What it means
JobBaseResource.validateJob throws FlowableObjectNotFoundException when the management service query returns no job for the given id, embedding the requested id in the message. It guards endpoints returning job details for jobs/timer jobs/suspended jobs/dead letter jobs.
Source
Thrown at modules/flowable-cmmn-rest/src/main/java/org/flowable/cmmn/rest/service/api/management/JobBaseResource.java:66
validateJob(job, jobId);
return job;
}
protected Job getDeadLetterJobById(String jobId) {
Job job = managementService.createDeadLetterJobQuery().jobId(jobId).singleResult();
validateJob(job, jobId);
return job;
}
protected HistoryJob getHistoryJobById(String jobId) {
HistoryJob job = managementService.createHistoryJobQuery().jobId(jobId).singleResult();
validateHistoryJob(job, jobId);
return job;
}
protected void validateJob(Job job, String jobId) {
if (job == null) {
throw new FlowableObjectNotFoundException("Could not find a job with id '" + jobId + "'.", Job.class);
}
if (restApiInterceptor != null) {
restApiInterceptor.accessJobInfoById(job);
}
}
protected void validateHistoryJob(HistoryJob job, String jobId) {
if (job == null) {
throw new FlowableObjectNotFoundException("Could not find a history job with id '" + jobId + "'.", HistoryJob.class);
}
if (restApiInterceptor != null) {
restApiInterceptor.accessHistoryJobInfoById(job);
}
}
}
View on GitHub (pinned to d6d39ce1c6)
Solutions
- Verify the job id from a fresh list of the relevant job collection.
- Check the correct engine/database and correct endpoint type (job vs timer vs dead letter).
- Handle 404 from these endpoints as 'job no longer exists' — for retry logic, re-query instead of retrying the same id.
Example fix
// before
Job job = jobBaseResource.getJobById(staleId);
// after
DeadLetterJobResponse job = firstOrNull(client.get("/cmmn-management/deadletter-jobs"));
if (job == null) { skip(); } else { use(job.getId()); } Defensive patterns
Strategy: try-catch
Validate before calling
// no pre-call validation possible beyond non-blank id
if (!jobId || jobId.trim() === "") throw new Error("jobId required"); Try / catch
try { job = getJob(id) } catch (e) { if (e.status === 404) { refreshJobList(); return; } throw e; } Prevention
- Fetch job ids from a fresh list immediately before use.
- Don't reuse ids across engine types (job vs timer vs deadletter) or engines.
- Expect jobs to disappear once executed — design retry logic around re-querying.
When it happens
Trigger: GET /cmmn-management/jobs/{jobId} (or timer-jobs/suspended-jobs/deadletter-jobs variants) with an id that does not exist, was already executed/deleted, or belongs to a different engine.
Common situations: Job executed and removed between listing and fetching; stale ids in scripts/retries; querying a CMMN job id via the BPM REST API or vice versa; typo in id.
Understand the failure class
Background: Record Not Found Errors: "not found", RecordNotFound, and "was not found" — what they mean and how to fix them — this error's family across 28 libraries.
Related errors
- Could not find a history job with id ''.
- Could not find a dead letter job(s) with id(s) {}
- Job with id '' doesn't have an exception stacktrace.
- The variable does not have a binary data stream.
- Invalid action, only 'move' or 'moveToHistoryJob' is support
AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11).
Data as JSON: /api/errors/76e3287948926f0f.
Report an issue: GitHub.