{"record":{"id":"aea6eacb5605e4ce","repo":"flowable/flowable-engine","slug":"use-dedicated-method-for-finding-external-worker-j","errorCode":null,"errorMessage":"Use dedicated method for finding external worker jobs to execute","messagePattern":"Use dedicated method for finding external worker jobs to execute","errorType":"exception","errorClass":"FlowableException","httpStatus":null,"severity":"error","filePath":"modules/flowable-job-service/src/main/java/org/flowable/job/service/impl/persistence/entity/data/impl/MybatisExternalWorkerJobDataManager.java","lineNumber":70,"sourceCode":"\n    @Override\n    public Class<? extends ExternalWorkerJobEntity> getManagedEntityClass() {\n        return ExternalWorkerJobEntityImpl.class;\n    }\n\n    @Override\n    public ExternalWorkerJobEntity create() {\n        return new ExternalWorkerJobEntityImpl();\n    }\n\n    @Override\n    public ExternalWorkerJobEntity findJobByCorrelationId(String correlationId) {\n        return getEntity(\"selectExternalWorkerJobByCorrelationId\", correlationId, externalWorkerJobByCorrelationIdMatcher, true);\n    }\n\n    @Override\n    public List<ExternalWorkerJobEntity> findJobsToExecute(List<String> enabledCategories, Page page) {\n        throw new FlowableException(\"Use dedicated method for finding external worker jobs to execute\");\n    }\n\n    @Override\n    public List<ExternalWorkerJobEntity> findJobsByExecutionId(final String executionId) {\n        DbSqlSession dbSqlSession = getDbSqlSession();\n\n        // If the execution has been inserted in the same command execution as this query, there can't be any in the database \n        if (isEntityInserted(dbSqlSession, \"execution\", executionId)) {\n            return getListFromCache(jobsByExecutionIdMatcher, executionId);\n        }\n\n        return getList(dbSqlSession, \"selectExternalWorkerJobsByExecutionId\", executionId, jobsByExecutionIdMatcher, true);\n    }\n\n    @Override\n    @SuppressWarnings(\"unchecked\")\n    public List<ExternalWorkerJobEntity> findJobsByProcessInstanceId(final String processInstanceId) {\n        return getDbSqlSession().selectList(\"selectExternalWorkerJobsByProcessInstanceId\", processInstanceId);","sourceCodeStart":52,"sourceCodeEnd":88,"githubUrl":"https://github.com/flowable/flowable-engine/blob/d6d39ce1c69ff244f2d9dc6af756a9b95e865586/modules/flowable-job-service/src/main/java/org/flowable/job/service/impl/persistence/entity/data/impl/MybatisExternalWorkerJobDataManager.java#L52-L88","documentation":"MybatisExternalWorkerJobDataManager.findJobsToExecute unconditionally throws FlowableException stating that a dedicated method must be used instead. This overridden data-manager method is intentionally not supported for external worker jobs (acquisition uses category-based dedicated queries such as findJobsToExecuteAsync in the acquire command path), so calling the generic lookup is a programming error.","triggerScenarios":"Calling findJobsToExecute(enabledCategories, page) directly on MybatisExternalWorkerJobDataManager, or invoking an internal API/async executor path that resolves the external worker job entity manager's generic findJobsToExecute instead of the dedicated external-worker acquisition query.","commonSituations":"Custom async executor or acquisition code written for regular jobs being reused against external worker jobs; direct use of internal data managers in custom extensions; version changes where Flowable routed acquisition through a new dedicated method and old code still calls the generic one.","solutions":["Use the dedicated external worker acquisition APIs (ExternalWorkerJobAcquireService / acquireJobsCmd) instead of the data manager's generic findJobsToExecute","For regular async jobs, use the regular JobEntityManager, not the external worker one","Filter categories via the dedicated acquisition query parameters rather than this method"],"exampleFix":"// before\nList<ExternalWorkerJobEntity> jobs = externalWorkerJobDataManager.findJobsToExecute(categories, new Page(0, 10));\n// after\nList<ExternalWorkerJob> jobs = externalWorkerJobAcquireService.acquireExternalWorkerJobs(lockDuration, categories, null, 10);","handlingStrategy":"try-catch","validationCode":"// Use the public service API, not the internal data manager:\n// externalWorkerJobAcquireService.acquireExternalWorkerJobs(...)\n// never call dataManager.findJobsToExecute for external worker jobs.","typeGuard":null,"tryCatchPattern":"try {\n    acquireViaGenericPath();\n} catch (FlowableException e) {\n    if (e.getMessage().contains(\"dedicated method\")) {\n        throw new IllegalStateException(\"Switch to ExternalWorkerJobAcquireService for external worker job acquisition\", e);\n    }\n    throw e;\n}","preventionTips":["Use ExternalWorkerJobAcquireService for external worker acquisition, never the data manager directly","Do not reuse regular-job executor internals for external worker jobs","When extending Flowable internals, check which dedicated methods the data manager exposes"],"tags":["unsupported-operation","flowable","internal-api"],"backgroundTag":"unsupported-operation","analyzedSha":"d6d39ce1c69ff244f2d9dc6af756a9b95e865586","analyzedAt":"2026-09-11T06:41:19.413Z","contentChangedAt":"2026-09-11T06:41:19.413Z","schemaVersion":2},"datasetVersion":"2026-09-18T11:17:12.947Z"}