apache/pulsar · error · IOException

Missing required permitMessages field for 'permit' command

Error message

Missing required permitMessages field for 'permit' command

What it means

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.

Solutions

  1. Always include an integer permitMessages field in every 'permit' command frame
  2. Update the client SDK/library so permit frames are serialized with permitMessages set
  3. Validate the outbound JSON on the client before sending (assert permitMessages is a non-negative number)
  4. If stopping consumption entirely, close the consumer instead of sending a zero/null permit

Example fix

// before
{"type":"permit"}
// after
{"type":"permit","permitMessages":10}
Defensive patterns

Strategy: validation

Validate before calling

if (cmd == null || cmd.getPermitMessages() == null || cmd.getPermitMessages() < 0) { throw new IllegalArgumentException("permit command requires non-negative permitMessages"); }

Type guard

boolean hasPermitMessages(CommandPermit cmd) { return cmd != null && cmd.getPermitMessages() != null && cmd.getPermitMessages() >= 0; }

Try / catch

try { handler.handlePermit(cmd); } catch (IOException e) { log.error("permit frame rejected: {}", e.getMessage()); closeSession(); }

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Understand the failure class

Background: "Missing required field" and "field is required" errors: why libraries reject payloads that omit mandatory fields — this error's family across 20 libraries.

Related errors


AI-assisted analysis of apache/pulsar@820761864e (2026-09-06). Data as JSON: /api/errors/e3c0bde26ca2d898. Report an issue: GitHub.

Appendix: source

Thrown at pulsar-websocket/src/main/java/org/apache/pulsar/websocket/ConsumerHandler.java:382

        MessageId originalMsgId = messageIdCache.asMap().remove(command.messageId);
        if (originalMsgId != null) {
            consumer.negativeAcknowledge(originalMsgId);
        } else {
            consumer.negativeAcknowledge(msgId);
        }
        checkResumeReceive();
    }

    private void handlePermit(ConsumerCommand command) throws IOException {
        log.debug()
                .attr("topic", consumer.getTopic())
                .attr("subscription", subscription)
                .attr("received", command.permitMessages)
                .attr("request", getSession().getRemoteSocketAddress())
                .log("/ ] Received permits request from");
        if (command.permitMessages == null) {
            throw new IOException("Missing required permitMessages field for 'permit' command");
        }
        if (this.pullMode) {
            int pending = pendingMessages.getAndAdd(-command.permitMessages);
            if (pending >= 0) {
                // Resume delivery
                receiveMessage();
            }
        }
    }

    @Override
    public void close() throws IOException {
        if (consumer != null) {
            if (!this.service.removeConsumer(this)) {
                log.warn().attr("topic", consumer.getTopic()).log("Failed to remove consumer handler");
            }
            consumer.closeAsync().thenAccept(x -> {
                log.debug().attr("topic", consumer.getTopic()).log("Closed consumer asynchronously");

View on GitHub (pinned to 820761864e)