flowable/flowable-engine · error · FlowableObjectNotFoundException
No dead letter job found with id '
Error message
No dead letter job found with id '
What it means
DeleteDeadLetterJobCmd looks up a dead letter job by id via the DeadLetterJobEntityManager before deleting it. When no row exists with that id, Flowable throws FlowableObjectNotFoundException carrying the id and referencing Job.class. This is the engine telling you the delete was invoked against an id that does not exist in the ACT_RU_DEADLETTER_JOB table.
Solutions
- Fetch the dead letter job first (managementService.getDeadLetterJobs / createDeadLetterJobQuery().deadLetterJobId(id)) and confirm the id exists before deleting.
- Verify you are not deleting the same job twice (guard with an existence check or idempotent handling of FlowableObjectNotFoundException).
- Check the job may have been moved out of the dead letter table (retried via moveDeadLetterJobToExecutableJobCmd) — delete from its current table instead.
- Log the raw id and compare with the database row in ACT_RU_DEADLETTER_JOB to rule out id truncation or wrong-engine lookup.
Example fix
// before
managementService.executeCommand(new DeleteDeadLetterJobCmd(deadLetterJobId));
// after
if (managementService.createDeadLetterJobQuery().deadLetterJobId(deadLetterJobId).count() > 0) {
managementService.executeCommand(new DeleteDeadLetterJobCmd(deadLetterJobId));
} Defensive patterns
Strategy: validation
Validate before calling
if (deadLetterJobId == null || managementService.createDeadLetterJobQuery().deadLetterJobId(deadLetterJobId).count() == 0) {
throw new IllegalArgumentException("Dead letter job does not exist: " + deadLetterJobId);
} Try / catch
try {
managementService.executeCommand(new DeleteDeadLetterJobCmd(deadLetterJobId));
} catch (FlowableObjectNotFoundException e) {
LOGGER.info("Dead letter job {} already gone", deadLetterJobId);
} Prevention
- Always resolve the id from a fresh dead letter job query right before deleting.
- Make cleanup routines idempotent against not-found.
- Log the id and engine name to catch cross-engine/wrong-table mistakes.
When it happens
Trigger: Calling ManagementService.executeCommand(new DeleteDeadLetterJobCmd(deadLetterJobId)) or an API that delegates to it (e.g. managementService.deleteJob on a dead-letter id) when the dead letter job was already deleted, never existed, or the id string is wrong/typo'd.
Common situations: Double-processing of an async failed job (one worker deletes the dead letter job, a retry path deletes it again); deleting after moving the job back to the timer/job tables; using an id from a different engine/process instance; stale UI listing after the job was resolved.
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
- No job found with id '
- Active execution could not be found with activity id
- Batch part with id ' ' does not have a batch part document.
- Batch with id ' ' does not have a batch document.
- Cannot associate execution by id: no execution with id '
AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11).
Data as JSON: /api/errors/c74b7a40a47e5bf1.
Report an issue: GitHub.
Appendix: source
Thrown at modules/flowable-job-service/src/main/java/org/flowable/job/service/impl/cmd/DeleteDeadLetterJobCmd.java:76
protected void sendCancelEvent(DeadLetterJobEntity jobToDelete) {
FlowableEventDispatcher eventDispatcher = jobServiceConfiguration.getEventDispatcher();
if (eventDispatcher != null && eventDispatcher.isEnabled()) {
eventDispatcher.dispatchEvent(FlowableJobEventBuilder.createEntityEvent(FlowableEngineEventType.JOB_CANCELED, jobToDelete),
jobServiceConfiguration.getEngineName());
}
}
protected DeadLetterJobEntity getJobToDelete(CommandContext commandContext) {
if (deadLetterJobId == null) {
throw new FlowableIllegalArgumentException("jobId is null");
}
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Deleting job {}", deadLetterJobId);
}
DeadLetterJobEntity job = jobServiceConfiguration.getDeadLetterJobEntityManager().findById(deadLetterJobId);
if (job == null) {
throw new FlowableObjectNotFoundException("No dead letter job found with id '" + deadLetterJobId + "'", Job.class);
}
return job;
}
}
View on GitHub (pinned to d6d39ce1c6)