{"record":{"id":"aa69b0e978927a1e","repo":"flowable/flowable-engine","slug":"topic-is-null","errorCode":null,"errorMessage":"topic is null","messagePattern":"topic is null","errorType":"exception","errorClass":"FlowableIllegalArgumentException","httpStatus":null,"severity":"error","filePath":"modules/flowable-job-service/src/main/java/org/flowable/job/service/impl/ExternalWorkerJobAcquireBuilderImpl.java","lineNumber":52,"sourceCode":"    protected final CommandExecutor commandExecutor;\n    protected final JobServiceConfiguration jobServiceConfiguration;\n\n    protected String topic;\n    protected Duration lockDuration;\n    protected String scopeType;\n    protected String tenantId;\n    protected String authorizedUser;\n    protected Collection<String> authorizedGroups;\n\n    public ExternalWorkerJobAcquireBuilderImpl(CommandExecutor commandExecutor, JobServiceConfiguration jobServiceConfiguration) {\n        this.commandExecutor = commandExecutor;\n        this.jobServiceConfiguration = jobServiceConfiguration;\n    }\n\n    @Override\n    public ExternalWorkerJobAcquireBuilder topic(String topic, Duration lockDuration) {\n        if (topic == null) {\n            throw new FlowableIllegalArgumentException(\"topic is null\");\n        }\n\n        if (lockDuration == null) {\n            throw new FlowableIllegalArgumentException(\"lockDuration is null\");\n        }\n\n        this.topic = topic;\n        this.lockDuration = lockDuration;\n        return this;\n    }\n\n    @Override\n    public ExternalWorkerJobAcquireBuilder onlyBpmn() {\n        if (ScopeTypes.CMMN.equals(scopeType)) {\n            throw new FlowableIllegalArgumentException(\"Cannot combine onlyCmmn() with onlyBpmn() in the same query\");\n        }\n\n        if (scopeType != null) {","sourceCodeStart":34,"sourceCodeEnd":70,"githubUrl":"https://github.com/flowable/flowable-engine/blob/d6d39ce1c69ff244f2d9dc6af756a9b95e865586/modules/flowable-job-service/src/main/java/org/flowable/job/service/impl/ExternalWorkerJobAcquireBuilderImpl.java#L34-L70","documentation":"ExternalWorkerJobAcquireBuilderImpl.topic() registers a topic with a lock duration for acquiring external worker jobs. A null topic cannot be matched against jobs, so Flowable throws FlowableIllegalArgumentException.","triggerScenarios":"Invoking builder.topic(null, someDuration), typically when the topic string comes from an uninitialized variable or config entry.","commonSituations":"Topic names loaded from missing configuration keys or empty optional lookups; refactoring that removed a default topic constant.","solutions":["Ensure the topic string is a non-null, non-empty value before calling topic()","Provide a default topic when configuration is missing","Fail fast upstream with a clear message if the topic is absent"],"exampleFix":"// before\nbuilder.topic(config.getTopic(), Duration.ofMinutes(1));\n// after\nString topic = config.getTopic();\nif (topic == null) throw new IllegalStateException(\"topic not configured\");\nbuilder.topic(topic, Duration.ofMinutes(1));","handlingStrategy":"validation","validationCode":"if (topic == null || topic.isEmpty()) throw new IllegalArgumentException(\"topic must be non-empty before acquire\");","typeGuard":"boolean validTopic(String t) { return t != null && !t.isEmpty(); }","tryCatchPattern":"try { builder.topic(topic, lockDuration); } catch (FlowableIllegalArgumentException e) { if (!\"topic is null\".equals(e.getMessage())) throw e; /* handle missing topic config */ }","preventionTips":["Validate topic configuration at application startup","Never pass through optional config values without defaults","Add null checks where topics are resolved from external sources"],"tags":["flowable","external-worker","null-argument","validation"],"backgroundTag":"null-argument","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"}