{"record":{"id":"d49ecb54664f583d","repo":"apache/rocketmq","slug":"pullcallback-is-null","errorCode":null,"errorMessage":"pullCallback is null","messagePattern":"pullCallback is null","errorType":"exception","errorClass":"MQClientException","httpStatus":null,"severity":"error","filePath":"client/src/main/java/org/apache/rocketmq/client/impl/consumer/DefaultMQPullConsumerImpl.java","lineNumber":523,"sourceCode":"        if (null == mq) {\n            throw new MQClientException(\"mq is null\", null);\n        }\n\n        if (offset < 0) {\n            throw new MQClientException(\"offset < 0\", null);\n        }\n\n        if (maxNums <= 0) {\n            throw new MQClientException(\"maxNums <= 0\", null);\n        }\n\n        if (maxSizeInBytes <= 0) {\n            throw new MQClientException(\"maxSizeInBytes <= 0\", null);\n        }\n\n\n        if (null == pullCallback) {\n            throw new MQClientException(\"pullCallback is null\", null);\n        }\n\n        this.subscriptionAutomatically(mq.getTopic());\n\n        try {\n            int sysFlag = PullSysFlag.buildSysFlag(false, block, true, false);\n\n            long timeoutMillis = block ? this.defaultMQPullConsumer.getConsumerTimeoutMillisWhenSuspend() : timeout;\n\n            boolean isTagType = ExpressionType.isTagType(subscriptionData.getExpressionType());\n            this.pullAPIWrapper.pullKernelImpl(\n                mq,\n                subscriptionData.getSubString(),\n                subscriptionData.getExpressionType(),\n                isTagType ? 0L : subscriptionData.getSubVersion(),\n                offset,\n                maxNums,\n                maxSizeInBytes,","sourceCodeStart":505,"sourceCodeEnd":541,"githubUrl":"https://github.com/apache/rocketmq/blob/293f5885719fc4aa3619446a1900f58ccfcfdd29/client/src/main/java/org/apache/rocketmq/client/impl/consumer/DefaultMQPullConsumerImpl.java#L505-L541","documentation":"Thrown by pullAsyncImpl when the PullCallback argument is null. Because the async API delivers its result exclusively through the callback, a null callback would make the result unreachable and lose pull outcomes; the client rejects it up front.","triggerScenarios":"DefaultMQPullConsumer.pullAsync(mq, expr, offset, maxNums, null); a callback field not yet initialized when the pull loop starts; refactoring inline anonymous PullCallback classes into fields and forgetting the assignment.","commonSituations":"Constructor-order bugs where pulls are scheduled before the callback is wired; test harnesses passing null intending to use a returned future (which the async API does not provide).","solutions":["Always supply a non-null PullCallback; implement both onSuccess and onException","Use the synchronous pull() if you want a return value instead of a callback","Initialize callback fields before starting any thread or timer that issues pulls"],"exampleFix":"// before\nconsumer.pullAsync(mq, \"*\", off, 32, null);\n\n// after\nconsumer.pullAsync(mq, \"*\", off, 32, new PullCallback() {\n    public void onSuccess(PullResult result) { /* handle */ }\n    public void onException(Throwable e) { /* log + retry */ }\n});","handlingStrategy":"validation","validationCode":"Objects.requireNonNull(pullCallback, \"pullCallback\");","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Implement both onSuccess and onException in every PullCallback","Use sync pull() when a return value is wanted"],"tags":["rocketmq","pull-consumer","null-check","callback","async-pull"],"backgroundTag":null,"analyzedSha":"293f5885719fc4aa3619446a1900f58ccfcfdd29","analyzedAt":"2026-08-14T11:50:13.822Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}