{"record":{"id":"329e68bf7cf16bef","repo":"flowable/flowable-engine","slug":"can-not-activate-job-jobid-parent-is-suspended","errorCode":null,"errorMessage":"Can not activate job ${jobId}. Parent is suspended.","messagePattern":"Can not activate job (.+?)\\. Parent is suspended\\.","errorType":"exception","errorClass":"FlowableIllegalArgumentException","httpStatus":null,"severity":"error","filePath":"modules/flowable-job-service/src/main/java/org/flowable/job/service/impl/JobServiceImpl.java","lineNumber":130,"sourceCode":"    }\n    \n    @Override\n    public List<DeadLetterJobEntity> findDeadLetterJobsByProcessInstanceId(String processInstanceId) {\n        return getDeadLetterJobEntityManager().findJobsByProcessInstanceId(processInstanceId);\n    }\n    \n    @Override\n    public void updateAllJobTypesTenantIdForDeployment(String deploymentId, String newTenantId) {\n        getJobEntityManager().updateJobTenantIdForDeployment(deploymentId, newTenantId);\n        getTimerJobEntityManager().updateJobTenantIdForDeployment(deploymentId, newTenantId);\n        getSuspendedJobEntityManager().updateJobTenantIdForDeployment(deploymentId, newTenantId);\n        getDeadLetterJobEntityManager().updateJobTenantIdForDeployment(deploymentId, newTenantId);\n    }\n    \n    @Override\n    public AbstractRuntimeJobEntity activateSuspendedJob(SuspendedJobEntity job) {\n        if (configuration.getJobParentStateResolver().isSuspended(job)) {\n            throw new FlowableIllegalArgumentException(\"Can not activate job \"+ job.getId() +\". Parent is suspended.\");\n        }\n        return getJobManager().activateSuspendedJob(job);\n    }\n\n    @Override\n    public SuspendedJobEntity moveJobToSuspendedJob(AbstractRuntimeJobEntity job) {\n        return getJobManager().moveJobToSuspendedJob(job);\n    }\n\n    @Override\n    public AbstractRuntimeJobEntity moveJobToDeadLetterJob(AbstractRuntimeJobEntity job) {\n        return getJobManager().moveJobToDeadLetterJob(job);\n    }\n\n    @Override\n    public JobEntity createJob() {\n        return getJobEntityManager().create();\n    }","sourceCodeStart":112,"sourceCodeEnd":148,"githubUrl":"https://github.com/flowable/flowable-engine/blob/d6d39ce1c69ff244f2d9dc6af756a9b95e865586/modules/flowable-job-service/src/main/java/org/flowable/job/service/impl/JobServiceImpl.java#L112-L148","documentation":"Flowable suspends process definitions/instances hierarchically: a job whose parent (process instance, process definition, or deployment) is suspended cannot be individually activated. JobServiceImpl.activateSuspendedJob() consults the JobParentStateResolver and throws FlowableIllegalArgumentException if the job's parent is still suspended, preventing an inconsistent state where an active job belongs to a suspended parent.","triggerScenarios":"Calling managementService.activateJob(jobId) (or activateJobByProcessInstanceId etc.) for a job whose owning process instance or process definition is currently suspended; trying to activate a job while its deployment-level suspension is still in effect.","commonSituations":"Administrators resuming a single job after a suspendAll() without first lifting the suspension on the parent process instance/definition; scripted recovery jobs that activate jobs while the whole deployment remains suspended; race conditions where suspension and activation happen concurrently.","solutions":["Activate the parent first: call managementService.activateProcessInstanceById(pid) or activateProcessDefinitionById(id) before activating the job","Lift the suspension at the level it was applied (process definition or deployment) using the matching activate* command","If per-job activation is intended, ensure the parent was never suspended or has already been re-activated, then retry"],"exampleFix":"// before\nmanagementService.activateJob(jobId); // parent still suspended -> error\n// after\nmanagementService.activateProcessInstanceById(processInstanceId);\nmanagementService.activateJob(jobId);","handlingStrategy":"try-catch","validationCode":"// Check parent state before activating\nboolean suspended = managementService.createProcessInstanceQuery()\n    .processInstanceId(pid)\n    .suspended()\n    .count() > 0;\nif (suspended) {\n    managementService.activateProcessInstanceById(pid);\n}","typeGuard":null,"tryCatchPattern":"try {\n    managementService.activateJob(jobId);\n} catch (FlowableIllegalArgumentException e) {\n    if (e.getMessage() != null && e.getMessage().contains(\"Parent is suspended\")) {\n        // activate parent, then retry once\n    } else {\n        throw e;\n    }\n}","preventionTips":["Track which level (job/instance/definition/deployment) you suspended at and resume at the same level","Check suspension state via queries before per-job activation","Avoid mixing suspendAll-style bulk suspension with per-job activation in automation"],"tags":["flowable","job-suspension","invalid-state","workflow"],"backgroundTag":"invalid-state-transition","analyzedSha":"d6d39ce1c69ff244f2d9dc6af756a9b95e865586","analyzedAt":"2026-09-11T06:41:19.413Z","contentChangedAt":"2026-09-11T06:41:19.413Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}