flowable/flowable-engine · error · FlowableException
Empty timer job can not be scheduled
Error message
Empty timer job can not be scheduled
What it means
TimerJobSchedulerImpl.scheduleTimer inserts a TimerJobEntity into the timer job store, but first guards against a null timer job with this FlowableException. A null timer job cannot be persisted or scheduled, and this indicates a bug in the code path that created it (e.g. scheduleTimerJob failing to create the entity).
Source
Thrown at modules/flowable-job-service/src/main/java/org/flowable/job/service/impl/asyncexecutor/TimerJobSchedulerImpl.java:62
if (newTimerJobEntity != null) {
if (jobServiceConfiguration.getInternalJobManager() != null) {
jobServiceConfiguration.getInternalJobManager().preRepeatedTimerSchedule(newTimerJobEntity, variableScope);
}
scheduleTimerJob(newTimerJobEntity);
}
}
}
@Override
public void scheduleTimerJob(TimerJobEntity timerJob) {
scheduleTimer(timerJob);
sendTimerScheduledEvent(timerJob);
}
protected void scheduleTimer(TimerJobEntity timerJob) {
if (timerJob == null) {
throw new FlowableException("Empty timer job can not be scheduled");
}
callJobProcessors(jobServiceConfiguration, JobProcessorContext.Phase.BEFORE_CREATE, timerJob);
jobServiceConfiguration.getTimerJobEntityManager().insert(timerJob);
}
protected void sendTimerScheduledEvent(TimerJobEntity timerJob) {
FlowableEventDispatcher eventDispatcher = jobServiceConfiguration.getEventDispatcher();
if (eventDispatcher != null && eventDispatcher.isEnabled()) {
eventDispatcher.dispatchEvent(FlowableJobEventBuilder.createEntityEvent(
FlowableEngineEventType.TIMER_SCHEDULED, timerJob), jobServiceConfiguration.getEngineName());
}
}
}
View on GitHub (pinned to d6d39ce1c6)
Solutions
- Ensure the TimerJobEntity is created (jobServiceConfiguration.getTimerJobEntityManager().create()) before scheduleTimerJob calls scheduleTimer.
- Null-check the timer job in calling code before invoking the scheduler.
- If triggered by boundary/boundary-event timers, verify the activity and process instance still exist so entity creation succeeds.
Example fix
// before TimerJobEntity timerJob = null; // creation skipped scheduler.scheduleTimerJob(...timerJob...); // after TimerJobEntity timerJob = jobServiceConfiguration.getTimerJobEntityManager().create(); timerJob.setJobHandlerType(...); // populate fields, then scheduler.scheduleTimerJob(...timerJob...);
Defensive patterns
Strategy: type-guard
Validate before calling
if (timerJob == null) {
throw new IllegalStateException("Refusing to schedule: timer job was not created");
} Type guard
boolean isSchedulable(TimerJobEntity job) { return job != null; } Try / catch
try { scheduler.scheduleTimerJob(...); } catch (FlowableException e) { if (e.getMessage().equals("Empty timer job can not be scheduled")) { timerJob = recreateTimerJob(context); scheduler.scheduleTimerJob(...timerJob...); } else throw e; } Prevention
- Always create TimerJobEntity via the timer job entity manager before scheduling.
- Null-check entities returned by custom factory/test stubs.
- Verify process instance and activity exist before scheduling boundary timers.
- Unit-test timer creation paths end-to-end with a real entity manager.
When it happens
Trigger: scheduleTimerJob (e.g. triggered by executeTimerJob for an async-continuation timer) creates/obtains a TimerJobEntity that is null and passes it to scheduleTimer.
Common situations: Custom job creation code returning null; entity manager stubs in tests returning null; timer jobs for deleted process instances where the create step silently skipped entity creation.
Related errors
- The timer job id is mandatory, but 'null' has been provided.
- Provided execution id is null
- jobId is null
- jobId and job is null
- Error retrieving app engine info
AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11).
Data as JSON: /api/errors/998c0f4a6792e312.
Report an issue: GitHub.