Repository navigation
Wait for more data when an RTU write request arrives split - #3067
Merged
janiversen merged 2 commits intoOct 20, 2026
Merged
Conversation
…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().
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
On
dev, a Modbus RTU server that receives a Write Multiple Coils, Write Multiple Registers or Read/Write Multiple Registers request in pieces raisesIndexErrorout of the framer.FramerRTU.decodewaits forMIN_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) crashescalculateRtuFrameSizebefore the frame can be sized. Serial reads often deliver a frame in pieces.This started with #3054: the removed
rtu_byte_count_posguard 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
IndexErrorfrom 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 likeexamples/custom_msg.pythat index into the frame. Every response PDU readsdata[2], whichMIN_SIZEalready guarantees.Second commit: the ASCII framer raised
ValueErrorfor a frame whose device id is not hex (:ZZ..., left over from #2917). The id is now parsed inside the existingexcept ValueError, so such a frame is skipped like any other bad hex.Tests:
test_rtu_partial_request_waits_for_more_datafeeds every prefix of a built FC15, FC16 and FC23 request and then the whole frame;test_ascii_non_hex_device_idcovers the ASCII case. Ondevthey fail withIndexError: index out of range(3) andValueError: invalid literal for int() with base 16(2); here they pass.test/framerandtest/pduare 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.