{"record":{"id":"b7ad59a3e7148d37","repo":"flowable/flowable-engine","slug":"could-not-find-a-dead-letter-job-with-id-jobid-b7ad59","errorCode":null,"errorMessage":"Could not find a dead letter job with id '${jobId}'.","messagePattern":"Could not find a dead letter job with id '(.+?)'\\.","errorType":"http","errorClass":"FlowableObjectNotFoundException","httpStatus":404,"severity":"error","filePath":"modules/flowable-rest/src/main/java/org/flowable/rest/service/api/management/JobResource.java","lineNumber":342,"sourceCode":"        if (MOVE_ACTION.equals(actionRequest.getAction())) {\n\n            /*\n             * Note that the jobType is checked to know which kind of move that needs to be done.\n             * The MOVE_TO_HISTORY_JOB_ACTION allows to specifically force the move to a history job and trigger the else part below.\n             */\n\n            try {\n                if (HistoryJobEntity.HISTORY_JOB_TYPE.equals(deadLetterJob.getJobType())) {\n                    managementService.moveDeadLetterJobToHistoryJob(deadLetterJob.getId(), processEngineConfiguration.getAsyncExecutorNumberOfRetries());\n\n                } else {\n                    managementService.moveDeadLetterJobToExecutableJob(deadLetterJob.getId(), processEngineConfiguration.getAsyncExecutorNumberOfRetries());\n\n                }\n\n            } catch (FlowableObjectNotFoundException e) {\n                // Re-throw to have consistent error-messaging across REST-API\n                throw new FlowableObjectNotFoundException(\"Could not find a dead letter job with id '\" + jobId + \"'.\", Job.class);\n            }\n\n        } else if (MOVE_TO_HISTORY_JOB_ACTION.equals(actionRequest.getAction())) {\n            try {\n                managementService.moveDeadLetterJobToHistoryJob(deadLetterJob.getId(), processEngineConfiguration.getAsyncHistoryExecutorNumberOfRetries());\n            } catch (FlowableObjectNotFoundException e) {\n                // Re-throw to have consistent error-messaging across REST-api\n                throw new FlowableObjectNotFoundException(\"Could not find a dead letter job with id '\" + jobId + \"'.\", Job.class);\n            }\n\n        }\n\n\n    }\n}\n","sourceCodeStart":324,"sourceCodeEnd":358,"githubUrl":"https://github.com/flowable/flowable-engine/blob/d6d39ce1c69ff244f2d9dc6af756a9b95e865586/modules/flowable-rest/src/main/java/org/flowable/rest/service/api/management/JobResource.java#L324-L358","documentation":"Flowable's REST job-resource re-throws FlowableObjectNotFoundException with this message when the dead-letter job action could not be performed because the job does not exist (or is no longer a dead-letter job). It wraps any FlowableObjectNotFoundException from the underlying managementService call to give consistent error messaging across the REST API. The Job.class entity type is attached so clients know which entity was not found.","triggerScenarios":"Calling POST /management/deadletter-jobs/{jobId} (executeDeadLetterJobAction) with an action such as MOVE to executable job when no dead-letter job with that jobId exists, the id is mistyped, or the job was already moved/executed and removed from the dead-letter table before the call.","commonSituations":"Stale job ids from a previous listing after a retry job was moved back to executable; racing with an admin UI that already moved the job; polling code that retries a move twice; typo'd or trimmed jobId from a script.","solutions":["Re-fetch the dead-letter job list (GET /management/deadletter-jobs) and confirm the jobId exists before calling the action","Check whether the job was already moved out of the dead-letter table (it may now be an executable/history job); use the corresponding resource instead","Correct the jobId in the client/script (check for truncation or whitespace)","Handle HTTP 404 from the REST call gracefully instead of treating it as a fatal failure"],"exampleFix":"// before\ngiven().post(\"/management/deadletter-jobs/\" + staleJobId);\n// after\nJob job = given().get(\"/management/deadletter-jobs/\" + staleJobId).as(Job.class); // 404 check\nif (job != null) { given().post(\"/management/deadletter-jobs/\" + staleJobId); }","handlingStrategy":"try-catch","validationCode":"// client-side pre-check against the REST API\nboolean exists = fetch(\"/management/deadletter-jobs\")\n    .filter(j -> j.id.equals(jobId))\n    .isPresent();\nif (!exists) throw new IllegalStateException(\"dead letter job \" + jobId + \" no longer present\");","typeGuard":"function isDeadLetterJob(job) { return job && typeof job.id === 'string' && job.id === jobId; }","tryCatchPattern":"try {\n    restTemplate.postForEntity(base + \"/management/deadletter-jobs/\" + jobId, action, Void.class);\n} catch (HttpClientErrorException.NotFound e) {\n    log.warn(\"Dead letter job {} already gone; re-listing\", jobId);\n    refreshDeadLetterJobs();\n}","preventionTips":["Always resolve the job id from a fresh GET /management/deadletter-jobs immediately before acting","Treat 404 on the action as 'already moved' rather than a failure in retry loops","Avoid caching dead-letter job ids across retries or long-running batches"],"tags":["rest-api","flowable","dead-letter-job","not-found"],"backgroundTag":"resource-not-found","analyzedSha":"d6d39ce1c69ff244f2d9dc6af756a9b95e865586","analyzedAt":"2026-09-11T06:41:19.413Z","contentChangedAt":"2026-09-11T06:41:19.413Z","schemaVersion":2},"datasetVersion":"2026-09-18T11:17:12.947Z"}