> For the complete documentation index, see [llms.txt](https://docs.umh.app/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.umh.app/benthos-umh/input/beckhoff-ads/troubleshooting.md).

# Troubleshooting

Start from the symptom. Every entry below refers to the plugin's own log output, which Benthos writes to stdout; adding `--log.level DEBUG` to the `benthos -c config.yaml` command adds the per-request detail. With no access to those logs, the one check worth making from the PLC side is whether a route exists for this client and what address it holds: see [Getting a route onto the PLC](/benthos-umh/input/beckhoff-ads/networking.md#getting-a-route-onto-the-plc).

| Symptom                                                           | Most likely cause                                                                              | Where to look                                                                                    |
| ----------------------------------------------------------------- | ---------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------ |
| Connects, registers symbols, no values arrive                     | `hostIP` is not the address the PLC sees                                                       | [Which kind of drop happened](#reading-a-disconnect)                                             |
| Log stops after `Connecting to PLC`                               | Wrong address, PLC off, or firewall on 48898                                                   | [Which kind of drop happened](#reading-a-disconnect)                                             |
| `route ... was registered but the PLC did not serve it`           | Route address or credentials                                                                   | [Repeated route failures back off](#why-retries-slow-down)                                       |
| Values arrive in bursts with gaps between                         | Connection dropping and reconnecting                                                           | [Reconnection](#reconnection)                                                                    |
| Values stop but the input keeps running                           | Notification delivery went silent                                                              | [Silent notification delivery](#silent-notification-delivery)                                    |
| The input reconnects every few seconds                            | A health check port-scanning 48898                                                             | [PLC connection check](/benthos-umh/input/beckhoff-ads/networking.md#plc-connection-check)       |
| Timestamps decades in the past or future                          | The PLC's own clock, used for notification samples                                             | [Symbols and metadata](/benthos-umh/input/beckhoff-ads/symbols-and-metadata.md#metadata-outputs) |
| `could not bind the inbound AMS port` and every request times out | The device answers on its own connection, and `48898` is taken on this host or blocked inbound | [How a route is matched](/benthos-umh/input/beckhoff-ads/how-it-works.md#how-a-route-is-matched) |

## Reading a disconnect

```mermaid
flowchart TD
  A["Connect fails, or a session drops"] --> B{"Did the PLC accept the TCP connection?"}
  B -->|no| C["targetAddress, PLC powered, firewall on 48898"]
  B -->|yes| D{"Did it serve any AMS frame?"}
  D -->|no| E["The PLC will not serve this route:<br/>check hostIP against the source address<br/>the PLC sees, and the credentials"]
  D -->|yes| F{"Do the drops arrive after a similar<br/>interval, while frame counts vary?"}
  F -->|yes| G["Check the route Address against the<br/>source address the PLC sees"]
  F -->|no| H["Transport or device-side reset:<br/>network path, or another client evicting this one"]
```

A failed connect logs a `hint` field naming the likely cause, and the PLC closing the connection is reported as one of two different cases:

| Log says                                                  | Meaning                                                    | Where to look                                                                                                                                                        |
| --------------------------------------------------------- | ---------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| the PLC did not accept a TCP connection                   | Nothing answered on the ADS port                           | `targetAddress`, PLC powered, firewall                                                                                                                               |
| closed it without serving a single AMS frame              | TCP accepted, but the route does not authorize this client | `username`/`password`, `hostIP` (set it explicitly behind NAT or a VPN), another client holding the route from the same host                                         |
| dropped a connection that was already carrying AMS frames | Transport or device-side reset, not a configuration error  | The network path, for VPN or subnet-router flaps. Or another client evicting this one: a Beckhoff AMS router serves one TCP connection per host and closes the older |

If those drops arrive after a similar interval each time while the frame counts vary, suspect configuration rather than the network: most often a route whose `Address` does not match the source the PLC sees. See [PLC behind a NATing gateway](/benthos-umh/input/beckhoff-ads/networking.md#plc-behind-a-nating-gateway-or-subnet-router).

## Reconnection

A session that is down is logged at error level: nothing is read while it lasts, and with `readType: notification` the samples in the gap are gone. Under UMH Core that also holds the bridge out of active until it recovers.

The plugin automatically reconnects when the TCP connection is lost (e.g. network cable unplugged, PLC restart). TCP keepalive is set to probe after 3 s idle, then every 2 s, five times, so a dead connection is declared after about 13 s. On reconnect, the plugin:

1. Re-establishes the TCP connection, retrying indefinitely on the backoff ramp below
2. Reloads the symbol table from the PLC
3. Re-subscribes all notification handles

No manual intervention is needed.

## A device that keeps dropping

Reconnect delays ramp `1s → 5s → 15s → 30s` and stay at the cap. A connection that drops repeatedly is treated as flapping and gets that cap as a cooldown. A PLC that resets an established connection every few seconds therefore spends most of its time waiting rather than reading. That is deliberate: every reconnect costs the PLC an accepted socket, and the default protects its socket table rather than stream continuity.

Where the samples matter more than the sockets, lower the cap, accepting one more accepted socket on the PLC per reconnect:

```yaml
maxReconnectInterval: 5s
```

The lower tiers are pulled down with it so the ramp stays valid. Check the drop verdict below first: if the drops are the route not being served, a faster reconnect makes it worse.

## Silent notification delivery

Notification delivery can stop **without the TCP connection dropping**, so there is no error and no reconnect. The [connection heartbeat](/benthos-umh/input/beckhoff-ads/how-it-works.md#the-connection-heartbeat) is what notices: once its beats stop for `notificationSilenceTimeout`, the subscriptions count as dead and `heartbeatRecovery` decides what happens next:

| Value                 | Behavior                                                                                                    | Use when                                                                                                                                                                                                                              |
| --------------------- | ----------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `immediate` (default) | Re-subscribes at once: one delete plus one add per symbol, in a burst                                       | The PLC answers reliably; fastest recovery from a genuine subscription death                                                                                                                                                          |
| `confirm`             | Waits for a second consecutive silent window, then re-subscribes                                            | The PLC stalls under load. Twice as slow to notice a real death, but one late beat no longer churns every handle                                                                                                                      |
| `rebuild`             | Drops the session and reconnects from scratch, re-registering every subscription as part of a fresh connect | The PLC ignores the churn. A device that is not answering times out on both the delete and the add, so every symbol costs two `requestTimeout` waits (5 s each by default) and never recovers, where a reconnect takes about a second |

An input that keeps running while delivering nothing is the failure this protects against: with `rebuild` the reconnect is visible in the logs, and the plugin reports itself disconnected so the pipeline restarts the input rather than sitting on dead handles.

## Why retries slow down

The plugin paces failed connects, and how long it waits depends on why the connect failed:

| Failure                                   | Next attempt                                                                 |
| ----------------------------------------- | ---------------------------------------------------------------------------- |
| Ordinary (dial refused, session rejected) | 1s, doubling to a 1 min ceiling; a rebooting PLC is still picked up promptly |
| The PLC will not serve the route          | 30s, doubling to 5 min                                                       |
| Three consecutive route failures          | Route registration is skipped entirely for 5 minutes                         |

The log says which is happening: `Waiting before the next connect attempt` with the delay, and on the third route failure a warning that registration is being skipped and that `hostIP` must be the address the PLC sees. Any successful connect clears all of it.

The pacing exists because retrying cannot fix a route the PLC will not serve. Every attempt costs the PLC a route registration and a socket, and enough of them will wedge its route table.

While registration is skipped the plugin also skips the probe, so the clean "route not served" verdict is unavailable until the window expires. That is the trade for not writing to the device's route table.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://docs.umh.app/benthos-umh/input/beckhoff-ads/troubleshooting.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
