EEZ Studio Error Flows: Test Local and Parent Catch Boundaries with Injected Failures
An error label is useful only if the failing operation reaches the Flow branch that updates it. In EEZ Studio, that route depends on where the error originates and which catch boundary is active. A native function returning a failure status, an expression evaluation error, and an explicit Error action are not automatically equivalent events.
Build a small failure-routing experiment before connecting the real operation. It should identify which handler ran, which success steps were skipped, and what state remains available for retry. A particularly important version check is whether an explicit Error action begins catch lookup in its own Flow or its parent.
The documentation and implementation need a boundary check
The official CatchError documentation describes catching errors in its Flow and descendant Flows. It also documents the component-level Catch error option, which adds an @Error output carrying a textual description. The Error action documentation says that its error can reach a catcher in the same Flow or an ancestor.
The inspected EEZ framework private.cpp implementation makes a more specific distinction. A component's own error output is considered first. Otherwise, catch lookup for an explicit Error component starts at the parent Flow; for other components it starts at the current Flow. Lookup then considers catch components and parent call boundaries as it moves upward.
That source is fixed at framework commit dc9af2d5004201d6c31273a4c4fcfe27fc20c234, resolved and read on October 19, 2026. Its bytes match the initially inspected master snapshot. It is not evidence that every released Studio simulator or embedded framework revision behaves identically. The discrepancy is a reason to test the installed pair, rather than promise same-Flow capture for every kind of failure.

Give each potential handler a visible identity
Create a parent test Flow that calls a child User Action. Place a visible status label on the test page and use distinct markers for the child's handler, the call site's @Error route, and the parent's CatchError route. Use separate counters if several failures can occur quickly; a final text value alone can hide an earlier update.
The child should have a recognizable normal-success step. Put another success marker after the call in the parent. These markers reveal whether failure routing accidentally continues through a success path or whether your expected continuation is missing.
Use one catcher per tested Flow at first. The inspected implementation scans component entries to find a catch component; designing around competing catchers in the same Flow would introduce an ordering dependency that this test does not need.
Record the Studio release and the framework revision actually linked into firmware. If you only know a branch name, record that limitation and identify the checked source bytes. A generated project and a separately updated framework can otherwise create a false comparison.
Inject two different failure classes
For the first class, choose a small component operation that produces a real Flow execution error in your installed version. Configure a reproducible invalid input and verify the exact error reported. Do not use a guessed arithmetic edge case and assume it must throw; some operations can return a value instead.
Run that case with the failing component's Catch error option enabled, then with it disabled. Observe the local @Error output separately from the surrounding Flow's CatchError. Keep the input and all other connections unchanged so that you are testing routing rather than a different failure.
For the second class, use an explicit Error action inside the child. Repeat the experiment with a child CatchError, a catch output on the parent's call component, and a parent CatchError, enabling one boundary at a time before testing combinations.
The important result is an observed routing matrix for your version. In particular, do not treat success with an ordinary component error as proof that an explicit Error action will reach the same catcher. The inspected implementation gives a concrete reason those paths can differ.
Translate native results deliberately
A device driver returning an error code is application data until the integration converts it into an observable Flow decision. Define the adapter's result contract: a stable success flag or status code, a diagnostic detail, and any values that are valid only on success.
One proposed design assigns the result to Flow-visible data and branches on it. The failure branch updates the UI and either handles the problem locally or invokes an explicit Error action to propagate it. That last choice inherits the catch-lookup behavior just tested; it is not a neutral replacement for a failed boolean.
Do not assume CatchError catches arbitrary C++ exceptions, operating-system faults, or every negative driver return value. The sources describe the Flow engine's error mechanism. Your native boundary must intentionally map its own failure model into that mechanism or into an ordinary result branch.
Likewise, displaying an error message does not prove that a partially completed device operation was rolled back. Record what changed before the failure and whether a retry is safe. Make the retry control available only under the application's actual recovery conditions.
Test recovery without losing the original failure
After each injected failure, confirm the handler marker, diagnostic detail, success counters and user-visible status. Then correct the input and run one successful attempt. A recovery path that still displays the old failure or never re-enables the initiating control is incomplete.
Keep technical details separate from the user-facing message. A stable code or request identifier helps correlate logs; a concise message explains what the operator can do next. Preserve the original failure while reporting a secondary problem in the error-display path, rather than replacing all context with the last message.
These checks are proposed experiments, not executed results. Their deliverable is a small project plus a versioned record of which boundaries caught which failures. That evidence lets the real native operation enter a known recovery design instead of relying on an error wire that has never carried an error.