{"record":{"id":"e3c0bde26ca2d898","repo":"apache/pulsar","slug":"missing-required-permitmessages-field-for-permit","errorCode":null,"errorMessage":"Missing required permitMessages field for 'permit' command","messagePattern":"Missing required permitMessages field for 'permit' command","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"error","filePath":"pulsar-websocket/src/main/java/org/apache/pulsar/websocket/ConsumerHandler.java","lineNumber":382,"sourceCode":"\n        MessageId originalMsgId = messageIdCache.asMap().remove(command.messageId);\n        if (originalMsgId != null) {\n            consumer.negativeAcknowledge(originalMsgId);\n        } else {\n            consumer.negativeAcknowledge(msgId);\n        }\n        checkResumeReceive();\n    }\n\n    private void handlePermit(ConsumerCommand command) throws IOException {\n        log.debug()\n                .attr(\"topic\", consumer.getTopic())\n                .attr(\"subscription\", subscription)\n                .attr(\"received\", command.permitMessages)\n                .attr(\"request\", getSession().getRemoteSocketAddress())\n                .log(\"/ ] Received permits request from\");\n        if (command.permitMessages == null) {\n            throw new IOException(\"Missing required permitMessages field for 'permit' command\");\n        }\n        if (this.pullMode) {\n            int pending = pendingMessages.getAndAdd(-command.permitMessages);\n            if (pending >= 0) {\n                // Resume delivery\n                receiveMessage();\n            }\n        }\n    }\n\n    @Override\n    public void close() throws IOException {\n        if (consumer != null) {\n            if (!this.service.removeConsumer(this)) {\n                log.warn().attr(\"topic\", consumer.getTopic()).log(\"Failed to remove consumer handler\");\n            }\n            consumer.closeAsync().thenAccept(x -> {\n                log.debug().attr(\"topic\", consumer.getTopic()).log(\"Closed consumer asynchronously\");","sourceCodeStart":364,"sourceCodeEnd":400,"githubUrl":"https://github.com/apache/pulsar/blob/820761864ed8e2a7d2e52dd9763ad2ae117c1395/pulsar-websocket/src/main/java/org/apache/pulsar/websocket/ConsumerHandler.java#L364-L400","documentation":"ConsumerHandler rejects a WebSocket 'permit' command that omits the required permitMessages field. The proxy uses permitMessages to resume (or further throttle) message delivery in pull mode; without a numeric value it cannot update the pending-credit counter, so it fails the frame with an IOException, which closes the consumer session.","triggerScenarios":"A WebSocket client sends a JSON frame with command type 'permit' but no permitMessages property (or sends null). handlePermit parses the command and throws before touching pendingMessages.","commonSituations":"Hand-rolled client code emitting permit frames; client SDK version mismatch where the producer of the frame serializes a null permit; a proxy or script forwarding partially-populated commands.","solutions":["Always include an integer permitMessages field in every 'permit' command frame","Update the client SDK/library so permit frames are serialized with permitMessages set","Validate the outbound JSON on the client before sending (assert permitMessages is a non-negative number)","If stopping consumption entirely, close the consumer instead of sending a zero/null permit"],"exampleFix":"// before\n{\"type\":\"permit\"}\n// after\n{\"type\":\"permit\",\"permitMessages\":10}","handlingStrategy":"validation","validationCode":"if (cmd == null || cmd.getPermitMessages() == null || cmd.getPermitMessages() < 0) { throw new IllegalArgumentException(\"permit command requires non-negative permitMessages\"); }","typeGuard":"boolean hasPermitMessages(CommandPermit cmd) { return cmd != null && cmd.getPermitMessages() != null && cmd.getPermitMessages() >= 0; }","tryCatchPattern":"try { handler.handlePermit(cmd); } catch (IOException e) { log.error(\"permit frame rejected: {}\", e.getMessage()); closeSession(); }","preventionTips":["Always serialize permitMessages in permit frames","Add client-side schema validation for outbound command JSON","Use an official Pulsar client SDK rather than hand-rolled WebSocket frames","Integration-test permit flow (pause/resume) in CI"],"tags":["websocket","protocol","validation"],"backgroundTag":"missing-required-field","analyzedSha":"820761864ed8e2a7d2e52dd9763ad2ae117c1395","analyzedAt":"2026-09-06T00:14:20.138Z","contentChangedAt":"2026-09-06T00:14:20.138Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}