Skip to content

Fix undecodable function-code exception identity - #2992

Merged
janiversen merged 2 commits into
pymodbus-dev:devfrom
sankalpsthakur:fix/2990-undecodable-fc-exception-tid
Jul 28, 2026
Merged

Fix undecodable function-code exception identity#2992
janiversen merged 2 commits into
pymodbus-dev:devfrom
sankalpsthakur:fix/2990-undecodable-fc-exception-tid

Conversation

@sankalpsthakur

Copy link
Copy Markdown
Contributor

Summary

When the server cannot decode a request function code (unassigned/reserved FC or serial noise), ServerRequestHandler.callback_data was building the exception response with two bugs:

  1. Hardcoded function code 40 (0x28) → every undecodable request produced exception FC 0xA8, unrelated to the request.
  2. transaction_id left at 0 → TCP clients correlating in-flight requests by transaction id could not match the response.

last_pdu is cleared at the start of framing, so the framer now attaches the already-decoded MBAP/RTU transaction_id and dev_id to the ModbusIOException. The server uses those attributes on the exception path, and builds ExceptionResponse(0x00, ILLEGAL_FUNCTION, ...) instead of the unrelated 40.

This matches maintainer guidance on #2990: echo transaction id, use 0x00 rather than inventing a function code from garbage.

Validation

pytest test/server/test_requesthandler.py  # 8 passed
pytest test/framer/                        # 279 passed
pytest test/transaction/test_transaction.py # 44 passed

New unit coverage:

  • framing attrs echoed on undecodable path
  • missing attrs fall back safely to zeros
  • real socket frame with unknown FC 0x09 echoes MBAP tid 0x1234

Fixes #2990

AI/LLM disclosure

  • AI coding tools (including Grok and/or Codex agent-assisted editing) were used to help draft or modify code and this PR description.
  • I reviewed the complete change, understand the reasoning, and ran the reported local tests before submitting.
  • This submission is original work of authorship under the project CLA / contributor terms; AI output was not pasted unreviewed.

When the server cannot decode a request function code, echo the framed
transaction and device ids on the illegal-function exception response,
and use function code 0x00 instead of the hardcoded 0x28.

Fixes pymodbus-dev#2990

Signed-off-by: Sankalp Thakur <sankalphimself@gmail.com>
Add transaction_id and dev_id as first-class fields so the type
checker accepts the undecodable-function exception path for pymodbus-dev#2990.

Signed-off-by: Sankalp Thakur <sankalphimself@gmail.com>

@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.

VERY nice way to solve the problem!

Feel free to search for ModbusIOException, I am pretty sure there are a number of places where transaction id and/or function code is known.

LGTM, thanks

@janiversen
janiversen merged commit 88eb731 into pymodbus-dev:dev Jul 28, 2026
16 checks passed
sankalpsthakur added a commit to sankalpsthakur/pymodbus that referenced this pull request Jul 28, 2026
Critical review of pymodbus-dev#2992/pymodbus-dev#2993 found register_message identity was dead
because DecodePDU swallowed ModbusIOException. Re-raise payload decode
errors, enrich framing tid/dev_id in the framer, use known fcode on the
server exception response when present, and forward the UDP peer addr.

Also lean the helper docstring, drop a private-method unit test, and
assert identity through handleFrame + sync execute paths.

Signed-off-by: Sankalp Thakur <sankalphimself@gmail.com>
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.

Server returns hardcoded function code (0x28) and transaction_id=0 for any undecodable function code

2 participants