{"record":{"id":"fc1f008594e50497","repo":"flowable/flowable-engine","slug":"externaljobid-must-not-be-empty","errorCode":null,"errorMessage":"externalJobId must not be empty","messagePattern":"externalJobId must not be empty","errorType":"validation","errorClass":"FlowableIllegalArgumentException","httpStatus":null,"severity":"error","filePath":"modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/cmd/AbstractExternalWorkerJobCmd.java","lineNumber":74,"sourceCode":"            CmmnEngineConfiguration cmmnEngineConfiguration = CommandContextUtil.getCmmnEngineConfiguration(commandContext);\n            new UnlockExclusiveJobCmd(externalWorkerJob, cmmnEngineConfiguration.getJobServiceConfiguration()).execute(commandContext);\n        }\n        return null;\n    }\n\n    protected abstract void runJobLogic(ExternalWorkerJobEntity externalWorkerJob, CommandContext commandContext);\n\n    protected void moveExternalWorkerJobToExecutableJob(ExternalWorkerJobEntity externalWorkerJob, CommandContext commandContext) {\n        CmmnEngineConfiguration cmmnEngineConfiguration = CommandContextUtil.getCmmnEngineConfiguration(commandContext);\n        cmmnEngineConfiguration.getJobServiceConfiguration().getJobManager().moveExternalWorkerJobToExecutableJob(externalWorkerJob);\n\n        cmmnEngineConfiguration.getIdentityLinkServiceConfiguration().getIdentityLinkService()\n                .deleteIdentityLinksByScopeIdAndType(externalWorkerJob.getCorrelationId(), ScopeTypes.EXTERNAL_WORKER);\n    }\n\n    protected ExternalWorkerJobEntity resolveJob(CommandContext commandContext) {\n        if (StringUtils.isEmpty(externalJobId)) {\n            throw new FlowableIllegalArgumentException(\"externalJobId must not be empty\");\n        }\n\n        if (StringUtils.isEmpty(workerId)) {\n            throw new FlowableIllegalArgumentException(\"workerId must not be empty\");\n        }\n\n        CmmnEngineConfiguration cmmnEngineConfiguration = CommandContextUtil.getCmmnEngineConfiguration(commandContext);\n        ExternalWorkerJobEntityManager externalWorkerJobEntityManager = cmmnEngineConfiguration.getJobServiceConfiguration().getExternalWorkerJobEntityManager();\n\n        ExternalWorkerJobEntity job = externalWorkerJobEntityManager.findById(externalJobId);\n\n        if (job == null) {\n            throw new FlowableObjectNotFoundException(\"No External Worker job found for id: \" + externalJobId, ExternalWorkerJobEntity.class);\n        }\n\n        if (!Objects.equals(workerId, job.getLockOwner())) {\n            throw new FlowableIllegalArgumentException(workerId + \" does not hold a lock on the requested job\");\n        }","sourceCodeStart":56,"sourceCodeEnd":92,"githubUrl":"https://github.com/flowable/flowable-engine/blob/d6d39ce1c69ff244f2d9dc6af756a9b95e865586/modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/cmd/AbstractExternalWorkerJobCmd.java#L56-L92","documentation":"FlowableIllegalArgumentException thrown by resolveJob in AbstractExternalWorkerJobCmd when the externalJobId supplied to the command (complete/acquire/failure) is null or empty. The command cannot locate the job without an id.","triggerScenarios":"Constructing an ExternalWorkerJobCompletionBuilder / failure command without calling externalJobId(...), or passing an empty string variable from the worker integration layer.","commonSituations":"Job id lost between acquire and complete phases (e.g., deserialized payload missing the id field); template code with placeholder id never filled in.","solutions":["Set the job id captured at acquisition: completionBuilder.externalJobId(job.getId()).","Validate the job id is non-empty in the worker before invoking the command.","Fix serialization of the acquisition result so the id survives to the completion step."],"exampleFix":"// before\ncmmnExternalWorkerServiceProvider.completeBuilder(workerId, null).complete();\n// after\ncmmnExternalWorkerServiceProvider.completeBuilder(workerId, acquiredJob.getId()).complete();","handlingStrategy":"validation","validationCode":"if (externalJobId == null || externalJobId.isBlank())\n    throw new IllegalArgumentException(\"externalJobId required before completing a job\");","typeGuard":null,"tryCatchPattern":"try { completeBuilder(workerId, externalJobId).complete(); }\ncatch (FlowableIllegalArgumentException e) { if (e.getMessage().equals(\"externalJobId must not be empty\")) { reacquireJob(); } }","preventionTips":["Carry the job id from the acquire result through the whole worker transaction","Fail fast in the worker when deserialized job payloads lack an id"],"tags":["cmmn","external-worker","validation"],"backgroundTag":"empty-required-field","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"}