The task watchdog is off. Here is what you lost
A watchdog is one checkbox per task, it is easy to switch off while debugging, and it is almost never switched back on. The project runs identically either way — right up to the cycle that doesn't end.
What the watchdog does
The task watchdog is a deadline on one cycle. You give the task a time limit and a sensitivity — how many consecutive overruns are tolerated — and if the task exceeds it, the runtime stops the application and puts the controller into exception. That sounds harsh until you consider the alternative.
Without it, a task that never finishes its cycle simply never finishes. Outputs freeze at their last written state. A valve that was opening stays opening; a pump that was running keeps running. The controller looks alive — the runtime is up, the connection is there, the display keeps drawing — while nothing is being computed.
In the export it looks like this
In the PLCopenXML export the task configuration carries the setting explicitly:
<Task name="MAIN" interval="T#20ms" priority="1" watchdog="false"/>
// same project, task that still has it:
<Task name="SLOW" interval="T#200ms" priority="10"
watchdog="true" watchdogTime="T#400ms" watchdogSensitivity="2"/>
How a cycle stops ending
The usual causes are dull and common: a WHILE whose exit condition depends on a value that stops changing, a loop bound taken from a variable that arrives as zero, a blocking library call waiting on a device that is no longer answering.
WHILE NOT bDone DO
// bDone is set by a device that just went offline
END_WHILE // no timeout, no EXIT — the cycle never returns
Why “it protects nothing anyway” is wrong
The common objection is that stopping the application is worse than freezing it, because a stopped PLC drops all outputs at once. On a process where that is genuinely more dangerous, the answer is not to disable the watchdog — it is to define the safe state in hardware, where it belongs: spring-return valves, contactors that drop out, an independent safety chain. A frozen controller with live outputs is not a safe state. It is the same failure, minus the alarm.
How to check your own project
In CODESYS: open each task under Task Configuration and look at the Watchdog group. Check every task, not the main one — the background task nobody thinks about is usually the one that was disabled during commissioning.
Two settings to look at while you are there. The watchdog time should be a multiple of the cycle time, not equal to it — a task that occasionally takes 21 ms on a 20 ms interval is normal, and a watchdog set at exactly 20 ms turns normal jitter into a stopped plant. And sensitivity of 1 means a single overrun triggers it; 2 is the usual compromise.
Catching it automatically
PLC Lint reads the task configuration out of a PLCopenXML export and reports tasks whose watchdog is off, together with the endless-loop patterns above. It runs locally or here on the export — 34 checks, about ten seconds, no signup.