GoodCompletesAsynchronously
GoodAsync methods
GoodCompletesAsynchronously is not an error and not a completion. The server accepted your request and will finish it later, so the output arguments you got back are not final. Watch the state or progress node the method belongs to, and never treat this status as done.
What you actually see
A method call returns success immediately for an operation that clearly cannot have finished - a recipe download, a software update, a long move - and the client reports the job complete.
Why it happens
- Long-running method that cannot answer synchronouslySome operations take seconds or minutes: a firmware update, a recipe transfer, a calibration cycle, a physical move. Blocking the service call for that long would hold a request thread and risk a timeout, so the server acknowledges acceptance and continues in the background.
- Write that is queued to a device rather than applied immediatelyA write forwarded to a device on its own scan cycle, or queued behind a communication buffer, may be acknowledged as accepted rather than as applied. The value reaches the device on a later cycle, so an immediate read-back can still show the old value.
- State-machine-based operation modelled in the address spaceCompanion models commonly represent long operations as a state machine with its own state, progress and result nodes rather than as a blocking method. The method starts a transition; the state machine reports the outcome. This status is the handover point between the two.
- Client not designed for asynchronous completionThe status is only a problem when the client ignores it. Code written against a synchronous assumption logs success, moves to the next step, and fails later for reasons that appear unrelated to the method call that actually did not finish.
- Server deferring work under loadA server that would normally complete a request inline may defer it when busy. The same call then behaves synchronously most of the time and asynchronously occasionally, which is the worst case for a client that only handles one path.
How to fix it
In diagnostic order: work down, do not skip ahead.
- Branch on the status, not on the absence of an errorCheck for this specific status explicitly. On seeing it, move into a wait-and-poll state rather than treating the output arguments as results. The output arguments at this point are placeholders, not answers.
- Find the state or progress node the operation reports toBrowse the object that owns the method for a state machine, a progress variable, a last-result node or a completion event. Companion device and machine models usually provide one. Monitor it rather than re-calling the method to find out what happened.
- Subscribe to the completion signal instead of polling hardWhere the operation raises an event or updates a state variable, subscribe to it. A monitored item on the state node with a modest publishing interval is far cheaper than a tight read loop and gives you the transition timestamp for free.
- Apply a timeout and a defined failure pathDecide how long the operation may take and what to do if the state never reaches completion. Without a timeout, an accepted-but-never-finished operation leaves your sequence blocked indefinitely with no error to report.
- Make the operation idempotent or guard against re-invocationA client that does not understand this status may call the method again. Guard on the state node before invoking, so a second call cannot start a duplicate download or a second move while the first is still running.
- Read back the effect, not just the statusFor a queued write, confirm the value at the device by reading it after a few scan cycles. For a recipe or configuration transfer, verify the resulting parameters. The status tells you the request was accepted; only the effect tells you it worked.
Where it shows up, by tool and stack
| Tool / stack | What to do there |
|---|---|
| UA-.NETStandard (C#) | CallAsync returns the method's StatusCode and output arguments together, so check the code before using the outputs. Pair the call with a monitored item on the operation's state node in the same helper. |
| node-opcua | session.call returns the status code and output arguments. Implement long-running method calls as a call-then-subscribe pattern rather than as a single awaited call. |
| asyncua (Python) | call_method returns the output arguments and raises only on a bad status, so this status passes through silently. Inspect the raw call result where you need to distinguish acceptance from completion. |
| Beckhoff TwinCAT | Methods that trigger PLC logic complete on a later task cycle, so acceptance and completion are genuinely separate moments. Model the completion in the program with a state or done flag the client can watch. |
| Siemens S7-1500 | Writes and method effects land on the CPU's own cycle, so an immediate read-back can show the previous value. Allow at least a cycle before verifying, and prefer an explicit acknowledgement variable in the program. |
| UaExpert | The method call dialog shows the returned status and output arguments, which makes it easy to confirm whether a given method on a given server answers synchronously or asynchronously before you write client code. |
What it looks like in the log
Call ns=4;s=Machine.StartRecipeDownload returned GoodCompletesAsynchronously
Awaiting state transition on ns=4;s=Machine.OperationState after asynchronous accept
Asynchronous operation still incomplete after 120 s; aborting per timeout policy
Confirm the fix
Confirm the operation's state node reaches a completion state and that the resulting configuration or value is what you asked for, rather than treating the method's immediate response as the outcome.
Stop it happening again
Handle this status explicitly in every method-call wrapper, model long operations as call-then-watch with a timeout, guard against re-invocation using the state node, and verify the effect rather than the acknowledgement.
Stuck on more than one of these? The troubleshooting clinic works through broken configurations end to end, on camera.
Troubleshooting clinic →Last verified 7 September 2026 against OPC UA 1.05.07. OPC UA Connect is an educational resource and is not affiliated with the OPC Foundation.