Skip to content

Wait for more data when an RTU write request arrives split - #3067

Merged
janiversen merged 2 commits into
pymodbus-dev:devfrom
sankalpsthakur:fix/rtu-split-write-request
Oct 20, 2026
Merged

janiversen merged 2 commits into
pymodbus-dev:devfrom
sankalpsthakur:fix/rtu-split-write-request

Conversation

@sankalpsthakur

Copy link
Copy Markdown
Contributor

On dev, a Modbus RTU server that receives a Write Multiple Coils, Write Multiple Registers or Read/Write Multiple Registers request in pieces raises IndexError out of the framer. FramerRTU.decode waits for MIN_SIZE (4) bytes before asking the PDU for the frame size, but those three requests read their byte count at index 6 (10 for Read/Write), so a first chunk of 4 to 6 bytes (4 to 10 for FC23) crashes calculateRtuFrameSize before the frame can be sized. Serial reads often deliver a frame in pieces.

This started with #3054: the removed rtu_byte_count_pos guard was what returned 0 for a short buffer. v3.16.1 is not affected. On Linux and macOS the exception shows up as "Exception in callback" from asyncio and the request still completes when the rest arrives; on the Windows poll path the exception ends the serial poll task and the server stops answering (seen with a mocked serial port).

The framer now treats an IndexError from the size calculation as "byte count not received yet" and waits for more data, the same as the existing "Frame - not ready" path. One place covers the three built-in requests and custom PDUs like examples/custom_msg.py that index into the frame. Every response PDU reads data[2], which MIN_SIZE already guarantees.

Second commit: the ASCII framer raised ValueError for a frame whose device id is not hex (:ZZ..., left over from #2917). The id is now parsed inside the existing except ValueError, so such a frame is skipped like any other bad hex.

Tests: test_rtu_partial_request_waits_for_more_data feeds every prefix of a built FC15, FC16 and FC23 request and then the whole frame; test_ascii_non_hex_device_id covers the ASCII case. On dev they fail with IndexError: index out of range (3) and ValueError: invalid literal for int() with base 16 (2); here they pass. test/framer and test/pdu are otherwise unchanged (266 and 679 passed).

AI disclosure: written with help from AI coding tools (Claude Code); I reviewed the change and checked the behaviour above before submitting.

…ount

x_calculateRtuFrameSize() of WriteMultipleCoilsRequest,
WriteMultipleRegistersRequest and ReadWriteMultipleRegistersRequest reads
the byte count at data[6] / data[10]. FramerRTU.decode() only guarantees
4 bytes, so a request split by the serial driver raised IndexError out of
data_received().

The generic helper removed in pymodbus-dev#3054 returned "not ready" for a short
buffer. Restore that in the framer, so it also covers user PDUs.
int(buffer[1:3], 16) was outside the try block that already handles bad
hex in the LRC and the payload, so a frame like b":ZZ0300010001FB\r\n"
raised ValueError out of data_received().

@janiversen janiversen left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, Thanks

@janiversen
janiversen merged commit a4e9206 into pymodbus-dev:dev Oct 20, 2026
16 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants