flowable/flowable-engine · info · FlowableObjectNotFoundException
Timer job with id '${jobId}' does not have an exception stac
Error message
Timer job with id '${jobId}' does not have an exception stacktrace. What it means
Same guard as the plain-job variant but for timer jobs: getTimerJobStacktrace throws FlowableObjectNotFoundException when managementService.getTimerJobExceptionStacktrace returns null, i.e. the timer job has no recorded exception.
Source
Thrown at modules/flowable-rest/src/main/java/org/flowable/rest/service/api/management/JobExceptionStacktraceResource.java:70
}
response.setContentType("text/plain");
return stackTrace;
}
@ApiOperation(value = "Get the exception stacktrace for a timer job", tags = { "Jobs" })
@ApiResponses(value = {
@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."),
@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.")
})
@GetMapping("/management/timer-jobs/{jobId}/exception-stacktrace")
public String getTimerJobStacktrace(@ApiParam(name = "jobId") @PathVariable String jobId, HttpServletResponse response) {
Job job = getTimerJobById(jobId);
String stackTrace = managementService.getTimerJobExceptionStacktrace(job.getId());
if (stackTrace == null) {
throw new FlowableObjectNotFoundException("Timer job with id '" + job.getId() + "' does not have an exception stacktrace.", String.class);
}
response.setContentType("text/plain");
return stackTrace;
}
@ApiOperation(value = "Get the exception stacktrace for a suspended job", tags = { "Jobs" })
@ApiResponses(value = {
@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."),
@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.")
})
@GetMapping("/management/suspended-jobs/{jobId}/exception-stacktrace")
public String getSuspendedJobStacktrace(@ApiParam(name = "jobId") @PathVariable String jobId, HttpServletResponse response) {
Job job = getSuspendedJobById(jobId);
String stackTrace = managementService.getSuspendedJobExceptionStacktrace(job.getId());
if (stackTrace == null) {View on GitHub (pinned to d6d39ce1c6)
Solutions
- Request stacktraces only for timer jobs that show a non-null exceptionMessage.
- For failed timer jobs, look in /management/deadletter-jobs/{id}/exception-stacktrace instead.
- Handle 404 as 'job healthy / no stacktrace' in monitoring code.
- Re-query the timer job to confirm it still exists after rescheduling.
Example fix
// before curl http://localhost:8080/flowable-rest/management/timer-jobs/3/exception-stacktrace // after: check failure state first JOB=$(curl http://localhost:8080/flowable-rest/management/timer-jobs/3) echo $JOB | jq -r '.exceptionMessage // empty' | grep -q . && \ curl http://localhost:8080/flowable-rest/management/timer-jobs/3/exception-stacktrace
Defensive patterns
Strategy: try-catch
Validate before calling
const job = await fetch(`${base}/management/timer-jobs/${jobId}`).then(r => r.json());
if (!job.exceptionMessage) return null; // healthy timer job Type guard
function hasRecordedFailure(job) { return !!job && typeof job.exceptionMessage === 'string' && job.exceptionMessage.length > 0; } Try / catch
try {
const trace = await getTimerJobStacktrace(jobId);
} catch (e) {
if (e.status === 404) return null;
throw e;
} Prevention
- Gate stacktrace fetches on the job's exceptionMessage field.
- Remember rescheduling clears prior failure details.
- Use the deadletter endpoint for terminal failures.
When it happens
Trigger: GET /management/timer-jobs/{jobId}/exception-stacktrace for a timer job that has not failed (never executed, or executing successfully).
Common situations: Polling stacktraces for all timer jobs in dashboards, timer jobs that were rescheduled (clearing prior failure data), or confusion between timer-jobs and deadletter-jobs endpoints for failed jobs.
Understand the failure class
Background: EmptyResultError / "no results found": when an API or scraper succeeds but returns zero rows — this error's family across 9 libraries.
Related errors
- Timer job with id '' doesn't have an exception stacktrace.
- Suspended job with id '' doesn't have an exception stacktrac
- Job with id '${jobId}' does not have an exception stacktrace
- Suspended job with id '${jobId}' does not have an exception
- No plan item instance found for id
AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11).
Data as JSON: /api/errors/498e746b3db4ae03.
Report an issue: GitHub.