{"record":{"id":"bf6cc200e57a2749","repo":"flowable/flowable-engine","slug":"suspended-job-with-id-jobid-does-not-have-an","errorCode":null,"errorMessage":"Suspended job with id '${jobId}' does not have an exception stacktrace.","messagePattern":"Suspended job with id '(.+?)' does not have an exception stacktrace\\.","errorType":"http","errorClass":"FlowableObjectNotFoundException","httpStatus":404,"severity":"info","filePath":"modules/flowable-rest/src/main/java/org/flowable/rest/service/api/management/JobExceptionStacktraceResource.java","lineNumber":89,"sourceCode":"        }\n\n        response.setContentType(\"text/plain\");\n        return stackTrace;\n    }\n\n    @ApiOperation(value = \"Get the exception stacktrace for a suspended job\", tags = { \"Jobs\" })\n    @ApiResponses(value = {\n            @ApiResponse(code = 200, message = \"Indicates the requested job was not found and the stacktrace has been returned. The response contains the raw stacktrace and always has a Content-type of text/plain.\"),\n            @ApiResponse(code = 404, message = \"Indicates the requested job was not found or the job does not have an exception stacktrace. Status-description contains additional information about the error.\")\n    })\n    @GetMapping(\"/management/suspended-jobs/{jobId}/exception-stacktrace\")\n    public String getSuspendedJobStacktrace(@ApiParam(name = \"jobId\") @PathVariable String jobId, HttpServletResponse response) {\n        Job job = getSuspendedJobById(jobId);\n\n        String stackTrace = managementService.getSuspendedJobExceptionStacktrace(job.getId());\n\n        if (stackTrace == null) {\n            throw new FlowableObjectNotFoundException(\"Suspended job with id '\" + job.getId() + \"' does not have an exception stacktrace.\", String.class);\n        }\n\n        response.setContentType(\"text/plain\");\n        return stackTrace;\n    }\n\n    @ApiOperation(value = \"Get the exception stacktrace for a deadletter job\", tags = { \"Jobs\" })\n    @ApiResponses(value = {\n            @ApiResponse(code = 200, message = \"Indicates the requested job was not found and the stacktrace has been returned. The response contains the raw stacktrace and always has a Content-type of text/plain.\"),\n            @ApiResponse(code = 404, message = \"Indicates the requested job was not found or the job does not have an exception stacktrace. Status-description contains additional information about the error.\")\n    })\n    @GetMapping(\"/management/deadletter-jobs/{jobId}/exception-stacktrace\")\n    public String getDeadLetterJobStacktrace(@ApiParam(name = \"jobId\") @PathVariable String jobId, HttpServletResponse response) {\n        Job job = getDeadLetterJobById(jobId);\n\n        String stackTrace = managementService.getDeadLetterJobExceptionStacktrace(job.getId());\n\n        if (stackTrace == null) {","sourceCodeStart":71,"sourceCodeEnd":107,"githubUrl":"https://github.com/flowable/flowable-engine/blob/d6d39ce1c69ff244f2d9dc6af756a9b95e865586/modules/flowable-rest/src/main/java/org/flowable/rest/service/api/management/JobExceptionStacktraceResource.java#L71-L107","documentation":"getSuspendedJobStacktrace throws FlowableObjectNotFoundException when managementService.getSuspendedJobExceptionStacktrace returns null for the given suspended job id — the job exists but no exception stacktrace is stored for it.","triggerScenarios":"GET /management/suspended-jobs/{jobId}/exception-stacktrace for a suspended job that has never failed execution.","commonSituations":"Suspended jobs created when a process definition was suspended (they are usually healthy), monitoring scripts iterating all suspended jobs, or jobs whose failure data was cleared on resume/retry.","solutions":["Only query stacktraces for suspended jobs known to have failed (exceptionMessage present).","If the job failed repeatedly, check dead-letter jobs instead of suspended jobs.","Handle 404 as 'no recorded failure' in automation.","Resume the job and let it fail into dead-letter if you need a full stacktrace for diagnosis."],"exampleFix":"// before\ncurl http://localhost:8080/flowable-rest/management/suspended-jobs/55/exception-stacktrace  // 404\n// after: gate on exceptionMessage\ncurl http://localhost:8080/flowable-rest/management/suspended-jobs/55 | jq '.exceptionMessage'\n# only fetch the stacktrace when it is non-null","handlingStrategy":"try-catch","validationCode":"const job = await fetch(`${base}/management/suspended-jobs/${jobId}`).then(r => r.json());\nif (!job.exceptionMessage) return null; // suspended but never failed","typeGuard":"function hasRecordedFailure(job) { return !!job && typeof job.exceptionMessage === 'string' && job.exceptionMessage.length > 0; }","tryCatchPattern":"try {\n  const trace = await getSuspendedJobStacktrace(jobId);\n} catch (e) {\n  if (e.status === 404) return null;\n  throw e;\n}","preventionTips":["Suspended jobs are usually healthy; only expect stacktraces for those with exceptionMessage set.","Do not blanket-poll stacktraces across all suspended jobs.","If diagnosis is needed, move/resume the job to dead-letter where the stacktrace persists."],"tags":["rest-api","suspended-job","stacktrace","not-found"],"backgroundTag":"empty-result-set","analyzedSha":"d6d39ce1c69ff244f2d9dc6af756a9b95e865586","analyzedAt":"2026-09-11T06:41:19.413Z","contentChangedAt":"2026-09-11T06:41:19.413Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}