flowable/flowable-engine · error · FlowableObjectNotFoundException

Could not find a job with id ''.

Error message

Could not find a job with id ''.

What it means

Thrown by DELETE /cmmn-management/jobs/{jobId} when the job disappears between the lookup and the deletion, or managementService.deleteJob cannot find it; the original exception is re-thrown with a standardized REST message. It guarantees consistent 404 semantics across the CMMN REST API.

Source

Thrown at modules/flowable-cmmn-rest/src/main/java/org/flowable/cmmn/rest/service/api/management/JobResource.java:134

        }

        return null;
    }

    @ApiOperation(value = "Delete a job", tags = { "Jobs" }, code = 204)
    @ApiResponses(value = {
            @ApiResponse(code = 204, message = "Indicates the job was found and has been deleted. Response-body is intentionally empty."),
            @ApiResponse(code = 404, message = "Indicates the requested job was not found..")
    })
    @DeleteMapping("/cmmn-management/jobs/{jobId}")
    @ResponseStatus(HttpStatus.NO_CONTENT)
    public void deleteJob(@ApiParam(name = "jobId") @PathVariable String jobId) {
        Job job = getJobById(jobId);
        try {
            managementService.deleteJob(job.getId());
        } catch (FlowableObjectNotFoundException e) {
            // Re-throw to have consistent error-messaging across REST-api
            throw new FlowableObjectNotFoundException("Could not find a job with id '" + jobId + "'.", Job.class);
        }
    }

    @ApiOperation(value = "Delete a timer job", tags = { "Jobs" }, code = 204)
    @ApiResponses(value = {
            @ApiResponse(code = 204, message = "Indicates the job was found and has been deleted. Response-body is intentionally empty."),
            @ApiResponse(code = 404, message = "Indicates the requested job was not found.")
    })
    @DeleteMapping("/cmmn-management/timer-jobs/{jobId}")
    @ResponseStatus(HttpStatus.NO_CONTENT)
    public void deleteTimerJob(@ApiParam(name = "jobId") @PathVariable String jobId) {
        Job job = getTimerJobById(jobId);
        try {
            managementService.deleteTimerJob(job.getId());
        } catch (FlowableObjectNotFoundException e) {
            // Re-throw to have consistent error-messaging across REST-api
            throw new FlowableObjectNotFoundException("Could not find a job with id '" + jobId + "'.", Job.class);
        }

View on GitHub (pinned to d6d39ce1c6)

Solutions

  1. Confirm the job exists: managementService.createJobQuery().jobId(jobId).singleResult() before deleting.
  2. Handle the 404 as idempotent success if the goal is just to get rid of the job.
  3. Re-fetch the job list to get fresh ids; avoid deleting from stale snapshots.

Example fix

// before
Job job = getJobById(jobId);
managementService.deleteJob(job.getId());
// after
Job job = managementService.createJobQuery().jobId(jobId).singleResult();
if (job != null) {
    managementService.deleteJob(job.getId());
}
Defensive patterns

Strategy: try-catch

Validate before calling

Job j = managementService.createJobQuery().jobId(jobId).singleResult();

Try / catch

try { managementService.deleteJob(jobId); }
catch (FlowableObjectNotFoundException e) { /* already gone — idempotent success */ }

Prevention

When it happens

Trigger: DELETE /cmmn-management/jobs/{jobId} for a jobId that does not exist (or was deleted by a concurrent worker / the engine between fetch and delete).

Common situations: Job already completed and swept by the async executor; duplicate DELETE calls (double-click / retried request); stale job ids from an old list response; typo'd 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


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