flowable/flowable-engine · error · ActivitiException

Error while firing timer: intermediate event activity ${nest

Error message

Error while firing timer: intermediate event activity ${nestedActivityId} not found

What it means

TimerCatchIntermediateEventJobHandler.execute extracts the nested activity id from the timer job configuration and resolves it against the process definition. If the activity no longer exists, the engine throws this ActivitiException because the timer fired for an activity that cannot be found to continue execution.

Source

Thrown at modules/flowable5-engine/src/main/java/org/activiti/engine/impl/jobexecutor/TimerCatchIntermediateEventJobHandler.java:46

    private static final Logger LOGGER = LoggerFactory.getLogger(TimerCatchIntermediateEventJobHandler.class);

    public static final String TYPE = "timer-intermediate-transition";

    @Override
    public String getType() {
        return TYPE;
    }

    @Override
    public void execute(Job job, String configuration, ExecutionEntity execution, CommandContext commandContext) {

        String nestedActivityId = TimerEventHandler.getActivityIdFromConfiguration(configuration);

        ActivityImpl intermediateEventActivity = execution.getProcessDefinition().findActivity(nestedActivityId);

        if (intermediateEventActivity == null) {
            throw new ActivitiException("Error while firing timer: intermediate event activity " + nestedActivityId + " not found");
        }

        try {
            if (commandContext.getEventDispatcher().isEnabled()) {
                commandContext.getEventDispatcher().dispatchEvent(
                        ActivitiEventBuilder.createEntityEvent(FlowableEngineEventType.TIMER_FIRED, job),
                        EngineConfigurationConstants.KEY_PROCESS_ENGINE_CONFIG);
            }

            if (!execution.getActivity().getId().equals(intermediateEventActivity.getId())) {
                execution.setActivity(intermediateEventActivity);
            }
            execution.signal(null, null);
        } catch (RuntimeException e) {
            LogMDC.putMDCExecution(execution);
            LOGGER.error("exception during timer execution", e);
            LogMDC.clear();
            throw e;

View on GitHub (pinned to d6d39ce1c6)

Solutions

  1. Delete the stale timer jobs referencing the old process definition version
  2. Fix the activity id in the job configuration to an existing activity
  3. Ensure process redeployments migrate or cancel pending timer jobs (e.g. with the process instance migration APIs)
  4. Keep activity ids stable across BPMN edits

Example fix

// remove stale job for an old definition version
managementService.createTimerJobQuery().processDefinitionId("oldDefId").list()
  .forEach(j -> managementService.deleteTimerJob(j.getId()));
Defensive patterns

Strategy: try-catch

Validate before calling

Activity act = repositoryService.createProcessDefinitionQuery()
    .processDefinitionId(job.getProcessDefinitionId()).singleResult() != null
    ? null : null; // verify the referenced activityId exists in the definition's BPMN before firing
String activityId = TimerEventHandler.getActivityIdFromConfiguration(job.getConfiguration());
if (!bpmnModel.getMainProcess().getFlowElement(activityId, true) ... ) { /* stale job */ }

Try / catch

try {
    managementService.moveDeadLetterJobToExecutableJob(jobId, retries);
} catch (FlowableException e) {
    if (e.getMessage() != null && e.getMessage().contains("not found")) {
        managementService.deleteTimerJob(staleJobId); // stale definition reference
    } else throw e;
}

Prevention

When it happens

Trigger: An intermediate-catch timer job fires after its process definition was redeployed/changed so the configured activityId no longer exists, or the job's configuration string points to a wrong activity id.

Common situations: Redeploying a new version of the process while old timer jobs still reference old activity ids; manual DB edits of job configuration; deleted/renamed boundary or intermediateCatchEvent ids; running stale jobs after migration.

Understand the failure class

Background: "Not found" and "does not exist" errors: why "Task not found", "No such folder", and "Can't find" fire when a lookup comes back empty — this error's family across 14 libraries.

Related errors


AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11). Data as JSON: /api/errors/05f9d84fa8be2b3e. Report an issue: GitHub.