Inbound and outbound packet-size checks differ, so a QoS 1 message just under MaxUserPayloadBytes is accepted but never delivered (blocks a persistent subscriber)
@abhiramaab ya está trabajando en esto.
Desde el 2/10/2026.
- #314 de @abhiramaab — cerrado sin fusionar
Evaluación
- Dificultad
- 4/5
- Tiempo estimado
- 3-5 días
- Aptitud para principiantes
- 55/100
- Tipo de issue
- Error
- Claridad
- Bastante claro
- Estado de actividad
- Activo
- Stack tecnológico
- java
- Área
- backend, networking
Línea de trabajo
Start with ChannelAttrs.setMaxPayload and the inbound MqttDecoder(maxUserPayloadSize), then compare that limit with MQTT3MessageSizer and MQTTPacketFilter on outbound delivery. Inspect MQTTSessionHandler.writeConfirmableSubMessage and the related resend behavior; done means accepted messages are deliverable or are dropped and confirmed without blocking the subscriber's in-flight window.
Escrito por el modelo de indexación a partir del texto del issue.
Descripción
Version: 4.0.0-incubating (standalone, default DevOnlySettingProvider)
Summary
MaxUserPayloadBytes (stored as TenantSettings.maxPacketSize) is enforced differently in the two directions:
- Inbound (publisher → broker): the replacement
MqttDecoder(maxPacketSize)compares the fixed header's remaining length R against the limit. A packet is accepted while R ≤ L. - Outbound (broker → subscriber):
MQTTPacketFilterdrops a packet whose full encoded size1 + varint(R) + Ris over the limit (MQTT3MessageSizer), reportingOversizePacketDroppedand never completing the write.
So a QoS 1 PUBLISH whose remaining length is within 3 bytes of the limit (R = L−2 … L for L = 16384) is accepted and PUBACKed from the publisher, stored in the subscriber's inbox, and then dropped on every delivery attempt. writeConfirmableSubMessage keeps it in the unconfirmed set and resend() retries it until MaxResendTimes. With a large MaxResendTimes, a persistent subscriber's in-flight window fills with undeliverable messages and no further QoS 1 is delivered to it until the session is reset.
For MQTT 5 subscribers this cannot be worked around from the client: MQTT5ConnectHandler rejects a client Maximum Packet Size above maxPacketSize (CONNACK 0x83), and MQTTPacketFilter uses min(clientMax, settings.maxPacketSize).
Reproduction
- Start the broker with
-DMaxUserPayloadBytes=16384(and a large-DMaxResendTimes). - Subscriber: MQTT 3.1.1,
cleanSession=false, QoS 1, manual acks. - Publisher (same tenant): QoS 1 publishes with remaining length 16382, 16383, 16384 (payload = R − 2 − topicLength − 2), followed by a small normal message.
- The publisher gets PUBACKs for all of them; the subscriber receives none (not even the normal message once ~8 undeliverable messages occupy the window).
Expected
Both directions use the same measure, e.g. the inbound decoder limit is maxPacketSize − 5 (the maximum fixed-header overhead), or the outbound filter compares the remaining length, so anything accepted inbound is deliverable to a subscriber with the same limit. Independently, MQTTSessionHandler.writeConfirmableSubMessage already drops-and-confirms a confirmable message for NoSubPermission, Duplicated and NoLocal; doing the same when the encoded size exceeds the subscriber's limit (report a drop event, confirm(packetId, false)) would stop an undeliverable message from occupying the in-flight window until MaxResendTimes.
Checked against main (2026-10-02, 1394131): still present. #279 ("Fix oversized packet mem leakage", merged 2026-08-31, not yet released) makes MQTTPacketFilter release the buffer and complete the write promise, but the message stays unconfirmed in the session, and the inbound MqttDecoder(maxUserPayloadSize) in ChannelAttrs.setMaxPayload still compares the remaining length.
Related: apache/bifromq#258 (resend cancelled by PUBACK), apache/bifromq#289 (resend chain stops after a MaxRetried drop), #279 (oversized-packet buffer leak).
- Lenguaje dominante
- Java
- Estrellas
- 805
- Forks
- 99
- Merge medio
- 12 h 35 min
- PR fusionados (30 d)
- 3
Preparar el entorno
- Incluye un Dockerfile o un archivo de Docker Compose
- Sin plantilla de pull request
- Sin guía de contribución
Primeros pasos
- Lee el issue completo y luego la guía de contribución del proyecto.
- Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
- Haz un fork del repositorio y trabaja en una rama.
- Abre un pull request que haga referencia al número del issue.
Más de apache/bifromq
-
[BUG] KVRangeRestorer leaves the restore future uncompleted when startRestore() throws, permanently wedging the rangePosiblemente ocupada @ImDanXie la tomó hace 34 días. Abierto
Dificultad 2/5 1-3 horas Aptitud para principiantes 88/100
-
[BUG] TopicUtil.isValidTopicFilter accepts "$share/g/" — a shared subscription with an empty filter that can never matchPosiblemente ocupada @efegokdemir la tomó hace 36 días. Abierto
Dificultad 2/5 1-3 horas Aptitud para principiantes 75/100
-
[BUG] UTF8Util.isWellFormed inverts the surrogate-pair check: valid non-BMP characters are rejected, lone surrogates acceptedPosiblemente ocupada @efegokdemir la tomó hace 36 días. Abierto
Dificultad 2/5 1-3 horas Aptitud para principiantes 75/100
-
Dificultad 4/5 3-5 días Aptitud para principiantes 48/100
-
[BUG] ManagedRequestPipeline.close() leaves in-flight request futures pending foreverPosiblemente ocupada @ImDanXie la tomó hace 34 días. Abierto
Dificultad 3/5 1-2 días Aptitud para principiantes 68/100
Todos los issues de apache/bifromq
Issues similares
-
[BUG] micronaut-serde-oracle-jdbc-json brings a second OJDBC driver onto the runtime classpathPosiblemente ocupada @ZARAYACH la tomó hoy. Abierto
Dificultad 2/5 1-3 horas Aptitud para principiantes 72/100
micronaut-projects/micronaut-serialization#1494 · 4 comentarios ·
Los mantenedores suelen responder en 2 días
-
bug
Dificultad 2/5 1-3 horas Aptitud para principiantes 73/100
Los mantenedores suelen responder en 2 días
-
code-health feature/sync OS/Android QA/Test-Plan-Specified QA/Yes
Dificultad 2/5 1-3 horas Aptitud para principiantes 75/100
brave/brave-browser#60327 ·
Los mantenedores suelen responder en 1 día
-
Type: Bug
Dificultad 2/5 1-3 horas Aptitud para principiantes 65/100
it-at-m/raumreservierung#383 ·
Los mantenedores suelen responder en 3 días
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 78/100
aws/context-ontology-accelerator#325 ·
Los mantenedores suelen responder en 1 día