Service errors and timeouts
A service error means the command itself failed. Unlike a Modbus exception response, there’s no result. The same error looks like this in each environment:
| Environment | Appearance |
|---|---|
| C | PDCOMM_MODBUS_SERVICE_ERROR (5) with the error buffer {"error":"<message>","ok":false} |
| C++, Qt, MFC | std::runtime_error whose what() is the whole error JSON |
| .NET | ModbusCommandException (derives from InvalidOperationException); Message is the message only, and Code is the code of license errors |
| Headless | An {"error":"<message>","ok":false} line and exit code 1 |
| MCP | isError true, with the message in content[0].text |
| GUI | <command> failed: <message> in the status line |
The messages below are verbatim. The OS error text inside Io(...) differs between operating systems.
Command format
Section titled “Command format”| Message | Cause and fix |
|---|---|
Action is required |
The action member is missing. |
Unknown service action |
The action name is wrong. Check the JSON command reference. |
key must be a string at line 1 column 2, EOF while parsing an object at line 2 column 0 and similar |
A JSON syntax error. The headless simulator and MCP take one object per line. |
Input exceeds one MiB |
A headless or MCP line is longer than 1 MiB. |
missing field `port` , unknown field `extra`, expected one of ... |
A configuration or model member is missing or unknown. |
PDU is required |
request or execute has no pdu. |
Invalid hex length, Invalid hex |
The hex string has an odd number of digits or a non-hex character. |
Expected a byte array or hex string |
pdu or bytes is neither a string nor an array of 0–255. |
Invalid unit |
unit is outside 0–255. |
Configuration
Section titled “Configuration”| Message | Cause and fix |
|---|---|
Invalid endpoint configuration |
One of: a wrong transport, role or parity value; unit outside 1–247; timeout_ms or ascii_timeout_ms of 0 or above 60000; turnaround_ms above 60000; baud of 0; stop_bits other than 1 or 2; parity none with stop_bits 1 |
Gateway requires a serial bus transport |
Set a gateway’s transport to rtu or ascii. |
Invalid gateway route |
A routes key is 0, or a value is 0 or above 247. |
Invalid Security configuration |
security is used with a serial transport, mode is wrong, or chain, private_key or trust is empty. |
invalid type: string "Invalid JSON", expected struct Security |
The JSON in the GUI’s Security tab doesn’t parse. |
Protocol is excluded from this build |
The SDK doesn’t include the configured transport or Security; check capabilities. |
Disconnect before changing configuration |
You can’t change the configuration while connected. disconnect first. |
Endpoint is already connected |
Already connected. disconnect before connecting again. |
Connection
Section titled “Connection”| Message | Cause and fix |
|---|---|
Invalid TCP address |
address isn’t in IP:port form. Host names such as localhost:1502 aren’t accepted; write 127.0.0.1:1502. |
Io(ConnectionRefused, "Connection refused (os error 61)") |
No server listens at that address. Check that the server connected first and uses the same port. |
Io(TimedOut, "connection timed out") |
The TCP connection wasn’t established within timeout_ms. Check the route, firewalls and the device’s power. |
Io(AddrInUse, "Address already in use (os error 48)") |
Another program holds the server port. Use another port or stop that program. |
Io(AddrNotAvailable, "Can't assign requested address (os error 49)") |
The server address IP isn’t an address of this computer. Use 0.0.0.0 or the computer’s real address. |
InvalidConfig |
The serial port is empty. |
Io(Other, "No such file or directory") |
The serial port path doesn’t exist. |
Io(Other, "Unable to acquire exclusive lock on serial port") |
Another program has the serial port open. |
Security(...), Config(...), Crypto(...) |
Modbus/TCP Security errors; see Security connection problems. |
Licenses
Section titled “Licenses”The SDK libraries (C, C++, .NET, Qt, MFC) check the license on connect. The headless and MCP simulators don’t check it, and the simulator GUI uses its embedded tool license. License error replies carry a code in addition to error, so your program can tell them apart.
code |
Message | Cause and fix |
|---|---|---|
license_required |
PDComm license required for module 'modbus' (<state>): … |
There’s no license for connect. It needs the modbus module, plus modbus-security when the configuration has security. Nothing was opened. license in the reply holds module, state, and license_id; look up state in license troubleshooting. Endpoints that are already connected keep working. |
license_invalid |
License text is required, license text contains no PDCOMM LICENSE block, license text contains no valid license (<reason>), or license text is larger than 1048576 bytes |
license_install has no text, the text has no license block with a valid signature, or it’s larger than 1 MiB. The license installed earlier stays. Pass the whole file you received, unchanged. |
host_id_unavailable |
Host id unavailable: <reason> |
host_id couldn’t read the machine id. In a container, create /etc/machine-id. See Host ids. |
A refused connect replies like this:
{"code":"license_required","error":"PDComm license required for module 'modbus' (missing): no valid license for this module was found. Existing connections keep running. Install a license with the license API, PDCOMM_LICENSE_FILE or a pdcomm.license file.","license":{"license_id":null,"module":"modbus","state":"missing"},"ok":false}Transactions
Section titled “Transactions”| Message | Cause and fix |
|---|---|
Connect a client before sending a request |
Not connected as a client. Sending request in the server role also gives this. |
Timeout |
No response within timeout_ms. See Timeouts below. |
Closed |
The TCP connection is already closed: after a timeout, after the peer closed it, or after an I/O error. state reports connected as false. connect again. |
Io(ConnectionReset, "Connection reset by peer (os error 54)") |
The peer reset the connection. A plain client talking to a Security server also gets this. |
Unsupported |
A TCP client tried to send a serial-line-only function (07, 08, 11, 12, 17). |
InvalidConfig |
A serial client sent something other than a write to unit 0, or a unit above 247. |
Protocol(Correlation) |
The response doesn’t match the request (another unit, function code or transaction identifier). Check for several devices answering at one address, and the gateway settings. |
Protocol(Length), Protocol(Value) |
The response’s length or values don’t fit the function. An exception response isn’t an error even when its code is undefined (such as 07); it’s a result with "status":"exception". |
Protocol(Checksum), Protocol(Encoding), Protocol(Address) |
A serial response has a wrong CRC or LRC, an invalid ASCII character or a wrong address. See Serial communication problems. |
Request PDU checks
Section titled “Request PDU checks”A PDComm client checks a request PDU before sending it and doesn’t send an invalid one. The message is then a single word:
| Message | Examples |
|---|---|
Length |
The length doesn’t fit the function: 0700, an empty PDU |
Value |
A quantity of 0 or above the limit, a wrong function 05 value: 0300000000 |
Address |
Address plus quantity beyond 65536, a wrong file reference: 03FFFF0002 |
Function |
An unsupported function or diagnostics sub-function: 0800130000 |
Running the same PDU with execute shows the server-side behavior instead: an exception response (01, 02 or 03).
Timeouts
Section titled “Timeouts”Timeout means the request was sent but no response arrived within timeout_ms. If it was a write, the device may already have applied it, so read the value before writing again.
What to check on TCP
- Make sure the peer is a Modbus server that answers. The port may be open but belong to another protocol’s service.
- Check the unit identifier. Some devices and gateways ignore unknown units.
- If the peer is a gateway, make
timeout_mslonger than the gateway’s serial wait. - If the peer is a server built with the SDK, check that the application keeps calling
poll. A server that stops polling still accepts connections but never answers. - In the
failedrecord of the diagnostic log, look attx_bytes(bytes sent),rx_partial_bytes(bytes of a partial response) andmax_poll_gap_us(SDK processing delay).
After a timeout, a TCP client closes the connection so that a late response can’t be paired with the next request. Later requests fail with Closed, so connect again.
For timeouts on a serial line, see Serial communication problems.
Wrong address
Section titled “Wrong address”A wrong address returns the value of another register without any error, or exception 02.
| Symptom | Common cause |
|---|---|
| You get the value of the neighboring register | You didn’t subtract 1 from a one-based manual number (40001), or subtracted 1 from an address that was already zero-based. |
| Exception 02 | You kept the table prefix digit: 40001 is address 0, not 40000. |
| The value is always 0 or unrelated | Wrong table: measurements are often input registers (04) and settings holding registers (03). |
| A 32-bit value is far off | The two registers are in the opposite order from the device (ABCD vs CDAB). |
| A negative number shows as 65000-something | You read a signed 16-bit value as unsigned. |
To confirm:
- Find a register with a fixed value in the manual, such as a device ID or firmware version, and read it first. The expected value proves your address base.
- Read the addresses around it to find where the expected value lives.
- Data model and addresses explains the conversion.
Data model and projects
Section titled “Data model and projects”| Message | Cause and fix |
|---|---|
Table is required, Address is required, Values are required |
A data_set member is missing. |
Unknown data table |
table must be coils, discrete_inputs, holding_registers or input_registers. |
Invalid data values |
values is empty, a bit table got a value other than 0 or 1, or the address is above 65535. |
Address outside configured table |
The address is outside the model’s table. Check start and size with data_get. |
Model is required |
model_set has no model. |
Bit table values must be zero or one |
Coils or discrete inputs contain a value other than 0 or 1. |
Invalid table range |
A table’s start address plus count leaves the 16-bit address range. |
Invalid file, FIFO or device identification model |
One of: file number 0 or more than 10000 records, more than 31 FIFO values, a missing object 0, 1 or 2, a reserved object 7–127, an object over 244 bytes, or a server_id outside 2–251 bytes. |
Invalid diagnostic register |
The register of diagnostics_set is above 65535. |
Project is required |
project_import has no project. |
Disconnect before loading a project |
Disconnect, then load. |
Unsupported Modbus project kind or version |
kind must be pdcomm.modbus.project and version 1. If you saved the whole {"ok":true,...} reply, save only result. |
Fault bytes are required, Fault input exceeds limit |
fault has no bytes, or more than 4096. |
Transport is excluded |
The transport of fault isn’t in the build. |
Serial transports are excluded |
serial_ports in a build without serial transports. |
Diagnostic log
Section titled “Diagnostic log”| Message | Cause and fix |
|---|---|
Logging configuration is required |
logging_configure has no config. |
Invalid logging level |
level must be error, warn, info, debug or trace. |
Unknown logging option |
The configuration has an unknown member. |
Logging limits are out of range |
max_bytes (8192 bytes to 1 GiB) or files (1–16) is out of range. |
Forensics requires debug or trace logging |
Enable forensics only at the debug or trace level. |
Cannot open logging sink |
The log file can’t be opened. Check that the folder exists and is writable. |
Logging flush failed |
Records weren’t written within two seconds, or writing failed. Check write_errors in logging_status. |
Headless runs and scenarios
Section titled “Headless runs and scenarios”| Message | Cause and fix |
|---|---|
Usage: pdcomm-modbus-headless [--scenario path] |
Wrong arguments (exit code 2). |
Scenario step N field <member> did not match |
A scenario expectation differs from the result (exit code 1). |
Expected fields must be an object |
expect isn’t an object. |
Scenario exceeds one MiB |
The scenario file is larger than 1 MiB. |
Endpoint poll failed: <error> |
A server’s or gateway’s poll failed and it disconnected. Read the error, then connect again. |