📝 MQTT 5 publish() silently succeeds when PUBACK or PUBREC rejects the message (#65)
Summary
MQTTClient.publish() returns normally when an MQTT 5 broker rejects a QoS 1 or QoS 2 PUBLISH with a negative acknowledgement reason code.For example, Mosquitto returns
0x87 (Not authorized) for an ACL-denied publication:Received PubAck(packet_id=1, reason_code=135, properties=None)
The message was not accepted by the broker, but
await client.publish(...) completes without an exception.Current behavior
For QoS 1,
_handle_puback() resolves the publish future successfully without checking PubAck.reason_code.For QoS 2,
_handle_pubrec() also ignores the reason code and sends PUBREL even when PUBREC contains 0x87. MQTT 5 only permits PUBREL after a PUBREC reason code below 0x80.The public
MQTTClient.publish() method discards the acknowledgement returned by MQTTProtocol.publish().Expected behavior
• PUBACK/PUBREC reason codes below
0x80, including 0x00 and 0x10 (No matching subscribers), complete successfully.• A PUBACK or PUBREC reason code of
0x80 or greater raises a public MQTTPublishError.• The exception exposes at least
reason_code; exposing the optional Reason String would also be useful.• A negative PUBREC completes and removes the QoS 2 flight, releases its packet identifier, and does not send PUBREL.
• The MQTT connection remains usable after the rejected operation.
• MQTT 3.1.1 behavior remains unchanged because PUBACK and PUBREC do not carry reason codes in that protocol version.
MQTTPublishError would be consistent with the existing MQTTSubscribeError.Protocol references
• MQTT 5.0 section 2.4: reason codes
0x80 and greater indicate failure.• MQTT 5.0 section 3.4.2.1: PUBACK
0x87 means the PUBLISH is not authorized.• MQTT 5.0 section 3.5.2.1: PUBREC has the same publish-rejection reason codes.
• MQTT 5.0 section 4.3.3: PUBREL is sent only after a PUBREC reason code below
0x80.• MQTT 5.0 section 4.4: a negative PUBACK/PUBREC acknowledges the packet for retry purposes, but does not make the publication successful.
• MQTT 3.1.1 section 3.3.5: when a PUBLISH is not authorized, the server must either send a positive acknowledgement or close the connection because the protocol has no negative publish acknowledgement.
Reproduction result
Reproduced with Mosquitto 2.1.2 and a read-only ACL:
MQTT 5 QoS 1:
Received PubAck(packet_id=1, reason_code=135, properties=None)
publish() returned normally
MQTT 5 QoS 2:
Received PubRec(packet_id=1, reason_code=135, properties=None)
QoS 2 PUBREC received, sent PUBREL
publish() returned normally
Mosquitto logs
Denied PUBLISH for both messages.Suggested tests
• QoS 1 negative PUBACK raises and releases the packet identifier.
• QoS 1
0x10 completes successfully.• QoS 2 negative PUBREC raises, releases the packet identifier, and sends no PUBREL.
• Optional Reason String is preserved in the exception.
• MQTT 3.1.1 ACK behavior is unchanged.
#good_first_issue #faststream #zmqtt
sent via relator