Repository navigation
Websocket multipart message does not work as expected #382
Description
Activity
HI @LSC-Labs , were you able to reproduce the issue on esp32 too by any chance ?
Reacted by LSC-LabsYes I tried the same with an ESP32
Sending the long message shows me a larger frame (1428 instead of 528) - but basically the same behavior ... ( I doubled the test data to be sure to get enough data inside )
output on console is :Connected clients: 1 / 1 total Free heap: 236476 index: 0, len: 2897, final: 1, opcode: 1, framelen: 1428 ws[/ws][2] text-message start ws[/ws][2] frame[0] start[2897] ws[/ws][2] frame[0] text[0 - 1428]: { "logToSerial": true, "traceMode": false, "devicename": "LSC-device", "devicepwd": "admin-geheim", "autorestart": "86400", "wifi": { "ap_channel": 3, "ap_hide": false, "bssid": "aa:bb:33:22:11:fe", "ap_ssid": "LSC-8eaa2c44", "ap_mode": "0", "dhcp": true, "fallback": false, "ssid": "WiFiOnICE", "wifi_pwd": "JoJoBaOel", "hostname": "LSC-Device" }, "dewswitch": { "dewdelta": 5.2, "hysteresis": 1.5, "min_outdoor": -10.3, "min_indoor": 10.1 }, "sensor": { "adjust_humidity": 5, "adjust_temp": -0.2, "physical": true, "web_key": "33445566778899abcdef", "web_lat": "23.556778", "web_long": "8.553641" }, "sensorOD": { "adjust_humidity": 0.3, "adjust_temp": 0.5, "physical": false, "web_key": "33445566778899abcdef", "web_lat": "23.556778", "web_long": "8.553641" }, "mqtt" : { "enabled": false, "autotopic": false, "host": "mqtt-host", "port": 1883, "syncrate": 60, "topic": "", "user": "", "passwd": "", "useha": false }, "rf433": { "enabled": true, "msgs": [ { "on": 4333356,"msg": 1, "type":1 }, { "on": 4333362,"msg": 0, "type":0 } index: 0, len: 2897, final: 1, opcode: 1, framelen: 1432 ws[/ws][2] text-message start ws[/ws][2] frame[0] start[2897] ws[/ws][2] frame[0] text[0 - 1432]: index: 0, len: 2897, final: 1, opcode: 1, framelen: 29 ws[/ws][2] text-message start ws[/ws][2] frame[0] start[2897] ws[/ws][2] frame[0] text[0 - 29]: PGVC␐␂ Y Connected clients: 1 / 1 totalAfter this call I immediately send also the "dd" input with the result:
(as you can see, also corrupted)Free heap: 236476 index: 0, len: 2897, final: 1, opcode: 1, framelen: 4 ws[/ws][2] text-message start ws[/ws][2] frame[0] start[2897] ws[/ws][2] frame[0] text[0 - 4]: ␄:dd Connected clients: 1 / 1 total Free heap: 236476After a while (without input - while I'm writing this test) I get the following messages - repeating:
[666084][E][AsyncWebSocket.cpp:436] _queueMessage(): Too many messages queued: discarding new messageThe build is using:
PLATFORM: Espressif 32 (6.9.0) > AZ-Delivery ESP-32 Dev Kit C V4 HARDWARE: ESP32 240MHz, 520KB RAM, 4MB Flash ... Scanning dependencies... Dependency Graph |-- WiFi @ 2.0.0 |-- ESPAsyncWebServer @ 3.9.6 |-- AsyncTCP @ 3.4.10 Building in debug modeThe chip is an ESP32 WROOM-32 (C4)
I forgot, I have to change the source code and replace the "os_printf" with "Serial.printf", cause the compiler could not find the definition... but I assume, this has no effect on.
Thx
PeterReacted by Mathieu Carbou[666084][E][AsyncWebSocket.cpp:436] _queueMessage(): Too many messages queued: discarding new message
when a ws message is sent, it does in a queue. if the async_tcp task is not able to process the sending faster than messages are enqueued, then the queue overflows.
I can reproduce the bug.
The bug was introduced in PR #353.
Safari sends an incomplete fragmented data for the mask so somebody did a PR to fix that but sadly broke backward compatibility because of the use of flag to keep track of the by count.
My fix sadly used the index which breaks fragmented frames.
Will find a way to fix it...
Reacted by LSC-Labs- addedType: BugSomething isn't workingSomething isn't workingand removed
on Feb 3, 2026 Great, thank you ....
... only to describe correctly, the tests I made, were done with
"Google Chrome - Version 144.0.7559.110 (Offizieller Build) (arm64)".
... the enqueued message I notified happened while writing the description of the error (in Safari).
I did not seen them before...
At this point, my network was connected to the access point the device opened (192.168.4.1) - without internet connection... so maybe this was a side effect.The main problem is the index/frame number/final flag - also as the corrupted data after the first frame was received in the function.
Would be great if you find a solution for it...Reacted by Mathieu Carbou- added a commit that references this issue
on Feb 3, 2026 - added 2 commits that reference this issue
on Feb 3, 2026 Result of https://github.com/ESP32Async/ESPAsyncWebServer#issue-353
- running again on ESP8266 D1-Mini...
... works as expected (maybe I did not get the meaning of the final flag - I expected the last frame - but
it works as described also in the example...
Connected clients: 1 / 1 total index: 0, len: 1447, final: 1, opcode: 1, framelen: 528 ws[/ws][1] text-message start ws[/ws][1] frame[0] start[1447] ws[/ws][1] frame[0] text[0 - 528]: { "logToSerial": true, "traceMode": false, "devicename": "LSC-device", "devicepwd": "admin-geheim", "autorestart": "86400", "wifi": { "ap_channel": 3, "ap_hide": false, "bssid": "aa:bb:33:22:11:fe", "ap_ssid": "LSC-8eaa2c44", "ap_mode": "0", "dhcp": true, "fallback": false, "ssid": "WiFiOnICE", "wifi_pwd": "JoJoBaOel", "hostname": "LSC-Device" }, "dewswitch": { "dewdelta": 5.2, "hysteresis index: 528, len: 1447, final: 1, opcode: 1, framelen: 536 ws[/ws][1] frame[0] text[528 - 1064]: ": 1.5, "min_outdoor": -10.3, "min_indoor": 10.1 }, "sensor": { "adjust_humidity": 5, "adjust_temp": -0.2, "physical": true, "web_key": "33445566778899abcdef", "web_lat": "23.556778", "web_long": "8.553641" }, "sensorOD": { "adjust_humidity": 0.3, "adjust_temp": 0.5, "physical": false, "web_key": "33445566778899abcdef", "web_lat": "23.556778", "web_long": "8.553641" }, "mqtt" : { "enabled" index: 1064, len: 1447, final: 1, opcode: 1, framelen: 383 ws[/ws][1] frame[0] text[1064 - 1447]: : false, "autotopic": false, "host": "mqtt-host", "port": 1883, "syncrate": 60, "topic": "", "user": "", "passwd": "", "useha": false }, "rf433": { "enabled": true, "msgs": [ { "on": 4333356,"msg": 1, "type":1 }, { "on": 4333362,"msg": 0, "type":0 } ] } } ws[/ws][1] frame[0] end[1447] ws[/ws][1] text-message end Connected clients: 1 / 1 totalReacted by Mathieu Carbou- running again on ESP8266 D1-Mini...
Result of https://github.com/ESP32Async/ESPAsyncWebServer#issue-353
- It is also working in the ESP32 environment:
Connected clients: 1 / 1 total Free heap: 236448 index: 0, len: 2897, final: 1, opcode: 1, framelen: 1428 ws[/ws][1] text-message start ws[/ws][1] frame[0] start[2897] ws[/ws][1] frame[0] text[0 - 1428]: { "logToSerial": true, "traceMode": false, "devicename": "LSC-device", "devicepwd": "admin-geheim", "autorestart": "86400", "wifi": { "ap_channel": 3, "ap_hide": false, "bssid": "aa:bb:33:22:11:fe", "ap_ssid": "LSC-8eaa2c44", "ap_mode": "0", "dhcp": true, "fallback": false, "ssid": "WiFiOnICE", "wifi_pwd": "JoJoBaOel", "hostname": "LSC-Device" }, "dewswitch": { "dewdelta": 5.2, "hysteresis": 1.5, "min_outdoor": -10.3, "min_indoor": 10.1 }, "sensor": { "adjust_humidity": 5, "adjust_temp": -0.2, "physical": true, "web_key": "33445566778899abcdef", "web_lat": "23.556778", "web_long": "8.553641" }, "sensorOD": { "adjust_humidity": 0.3, "adjust_temp": 0.5, "physical": false, "web_key": "33445566778899abcdef", "web_lat": "23.556778", "web_long": "8.553641" }, "mqtt" : { "enabled": false, "autotopic": false, "host": "mqtt-host", "port": 1883, "syncrate": 60, "topic": "", "user": "", "passwd": "", "useha": false }, "rf433": { "enabled": true, "msgs": [ { "on": 4333356,"msg": 1, "type":1 }, { "on": 4333362,"msg": 0, "type":0 } index: 1428, len: 2897, final: 1, opcode: 1, framelen: 1436 ws[/ws][1] frame[0] text[1428 - 2864]: ] } }+++{ "logToSerial": true, "traceMode": false, "devicename": "LSC-device", "devicepwd": "admin-geheim", "autorestart": "86400", "wifi": { "ap_channel": 3, "ap_hide": false, "bssid": "aa:bb:33:22:11:fe", "ap_ssid": "LSC-8eaa2c44", "ap_mode": "0", "dhcp": true, "fallback": false, "ssid": "WiFiOnICE", "wifi_pwd": "JoJoBaOel", "hostname": "LSC-Device" }, "dewswitch": { "dewdelta": 5.2, "hysteresis": 1.5, "min_outdoor": -10.3, "min_indoor": 10.1 }, "sensor": { "adjust_humidity": 5, "adjust_temp": -0.2, "physical": true, "web_key": "33445566778899abcdef", "web_lat": "23.556778", "web_long": "8.553641" }, "sensorOD": { "adjust_humidity": 0.3, "adjust_temp": 0.5, "physical": false, "web_key": "33445566778899abcdef", "web_lat": "23.556778", "web_long": "8.553641" }, "mqtt" : { "enabled": false, "autotopic": false, "host": "mqtt-host", "port": 1883, "syncrate": 60, "topic": "", "user": "", "passwd": "", "useha": false }, "rf433": { "enabled": true, "msgs": [ { "on": 4333356,"msg": 1, "type":1 }, { "on": 4333362,"msg": 0, index: 2864, len: 2897, final: 1, opcode: 1, framelen: 33 ws[/ws][1] frame[0] text[2864 - 2897]: "type":0 } ] } } ws[/ws][1] frame[0] end[2897] ws[/ws][1] text-message end Connected clients: 1 / 1 total Free heap: 236448Reacted by Mathieu Carbou- ... works as expected (maybe I did not get the meaning of the final flag - I expected the last frame - but
this final flag is weird indeed. I would have expected it to for like the upload handler, which means only set to 1 when the final fragment is received.
But instead, it is 1 for the last websocket frame. and a websocket frame can be up to 2^63 bytes long if I am not making a mistake. In the header:
typedef struct { /** Message type as defined by enum AwsFrameType. * Note: Applications will only see WS_TEXT and WS_BINARY. * All other types are handled by the library. */ uint8_t message_opcode; /** Frame number of a fragmented message. */ uint32_t num; /** Is this the last frame in a fragmented message ?*/ uint8_t final; /** Is this frame masked? */ uint8_t masked; /** Message type as defined by enum AwsFrameType. * This value is the same as message_opcode for non-fragmented * messages, but may also be WS_CONTINUATION in a fragmented message. */ uint8_t opcode; /** Length of the current frame. * This equals the total length of the message if num == 0 && final == true */ uint64_t len; /** Mask key */ uint8_t mask[4]; /** Offset of the data inside the current frame. */ uint64_t index; } AwsFrameInfo;
We have 3 levels:
- A WebSocket message
- Which can be split into WebSocket frames
- And any of that, even control frames, can be sent fragmented. For example Safari sends only a few bytes for some control frames then sends the rest.
So in theory, on an MCU, I would expect that everyone should see final == 1, and frame count should not increase, which is also the flag read from the websocket spec in the header of a starting frame.
Only TCP fragmentation could happen.
Reacted by LSC-LabsThe rest of the team will review hopefully this week and if that's the case I will be able to issue a release this week-end.
Reacted by LSC-LabsNote in your trace:
index: 1064, len: 1447, final: 1, opcode: 1, framelen: 383framelenis not a frame length but instead this is a TCP fragment of the same websocket frame ;-)Reacted by LSC-Labs- added a commit that references this issue
on Feb 8, 2026 Thanks for the fix on this. I was banging my head on why my JSON wasn't working from one of my devices, yet others were (using WebSocketsClient). My device (esp32p4) running esp_websocket_client was sending the JSON to an esp32 nano and it was fragmenting the message into two frames, 2 bytes for the first one every time and then the remainder of the frame (no matter the size I used (18 bytes, 63 bytes, 88 bytes), but the contents was garbage. I installed the latest commit and now it shows up as one frame instead of two, complete, JSON is valid again.
Platform
ESP8266
IDE / Tooling
PlatformIO
What happened?
I tried to send from the browser a json file (size about 1k) via web socket to the module.
I installed a new environment to avoid side effects and I used the code from the exsample folder: "WebSocket.ino"
The code is working with single frames and works as expected...
Then I inserted the code from https://github.com/ESP32Async/ESPAsyncWebServer/wiki#async-websocket-event to get also the
multipart message to receive the large messages.
Output is (i inserted framelen with the parameter len to visualize it):
I'm using
Dependency Graph
|-- ESP8266WiFi @ 1.0
|-- ESPAsyncTCP @ 2.0.0
|-- ESPAsyncWebServer @ 3.9.6
Building in debug mode
Thanks
Peter
Stack Trace
No Stack Trace, cause the application did not crash..
Minimal Reproductible Example (MRE)
Source code:
Test data:
I confirm that: