IF/ELSE, FOR, WHILE, TRY/EXCEPT, BREAK, CONTINUE, and Control Flow: Diagnostics, Failure Modes, and Production Practices
Diagnose unbounded loops, swallowed assertions, unsafe expression construction, misplaced BREAK/CONTINUE, string-truthiness surprises, and retry-without-evidence patterns using the smallest controlled reproduction.
Learning objectives
- Diagnose control-flow failures by separating parse/structure, expression, keyword, external-state, and result layers.
- Recognize broad EXCEPT and status-conversion patterns that turn real failures into misleading PASS results.
- Identify unbounded or oversized WHILE loops and replace them with explicit domain budgets.
- Explain why BREAK/CONTINUE placement and string truthiness can produce surprising behavior.
- Preserve first-failure evidence and repair the smallest control boundary without retries or result deletion.
Current compatibility baseline. Verified
2026-08-31: Robot Framework 7.4.2 is the current stable release;
7.5b1 is a pre-release and is not required in this chapter. Native
IF/ELSE arrived in Robot Framework 4.0;
WHILE, TRY/EXCEPT, BREAK,
CONTINUE, and inline IF are available in
modern Robot Framework 5.0+ syntax. Robot Framework 7.4.2 gives
WHILE a default 10,000-iteration limit; production
examples here set a smaller explicit limit.
1. Diagnostic sequence
-
Preserve the failing
output.xml,log.html,report.html, exact command, and any local trace. - Confirm Robot/Python version and executed suite path.
-
Validate parse structure: every native block has correct markers
and
END. -
Inspect condition inputs and whether
${var}replacement or$varobject access was intended. - Inspect the first failing keyword and exact message before looking at recovery.
- Check whether EXCEPT matching, BREAK/CONTINUE, or a loop limit altered the path.
- Inspect external state only if the executed keywords actually touched it.
- Apply the least destructive correction and rerun the smallest slice.
2. Failure mode: an effectively unbounded WHILE
This example disables the framework limit and can run forever. It is intentionally unsafe and must not be executed:
*** Test Cases ***
DO NOT RUN — Infinite Loop
WHILE True limit=NONE
Log no convergence condition
END
The repair is not “add a bigger sleep.” Define the expected convergence signal and a small count/time budget. If each iteration calls an external system, record attempt number and observed state so the final failure explains what happened.
3. Failure mode: broad EXCEPT hides an assertion
*** Test Cases ***
Broken Recovery
TRY
Should Be Equal actual expected
EXCEPT AS ${error}
Log ignored=${error}
END
Log Test now continues and may pass — misleading.
The assertion is the test’s evidence; catching it broadly defeats the test. Repair by removing recovery, or catch only a known operational failure with a stable contract:
TRY
Validate Synthetic State transient
EXCEPT transient:* type=GLOB AS ${error}
Log Expected transient condition: ${error}
END
4. Failure mode: string truthiness assumptions
Python expression truthiness treats any non-empty string as true.
The text "False" is therefore truthy. If a
command-line/environment source yields text, compare or convert
deliberately instead of writing IF $enabled and
assuming semantic boolean behavior.
VAR ${enabled_text} False
IF $enabled_text == "True"
Log enabled
ELSE
Log disabled
END
5. Failure mode: BREAK inside a called keyword
*** Test Cases ***
Broken Loop Control
FOR ${item} IN one two
Decide To Break ${item}
END
*** Keywords ***
Decide To Break
[Arguments] ${item}
IF $item == "two"
BREAK
END
This is invalid because BREAK is not in the active loop
body. Return a decision instead:
FOR ${item} IN one two
${stop}= Should Stop ${item}
IF ${stop} BREAK
END
6. Failure mode: constructing executable expressions from external text
Do not build strings such as "${external} == 'ok'" and
feed them to Evaluate or a condition. If
${external} is not trusted, it can alter the
expression. Keep the expression static and pass external content
through the evaluator namespace using $external.
7. Failure mode: retry loops without first-failure evidence
A loop that catches every failure, increments an attempt, and retries can erase the most informative first error. If polling is legitimate, log each observed state and catch only the transient class that authorizes another attempt. Permanent validation failures must leave the loop immediately.
Poll With Narrow Recovery
[Arguments] ${max}=4
${stop}= Evaluate int($max) + 1
FOR ${attempt} IN RANGE 1 ${stop}
TRY
${state}= Read Synthetic State ${attempt}
Should Not Be Equal ${state} invalid
EXCEPT transient:* type=GLOB AS ${error}
Log attempt=${attempt}; transient=${error}
CONTINUE
END
RETURN ${state}
END
Fail No successful state in ${max} attempts
8. Failure mode: wrapper-heavy control hides structure
New suites should not build nested Run Keyword If plus
Exit For Loop If constructs when native
IF/BREAK expresses the same path directly.
The wrapper style is still supported for compatibility and dynamic
dispatch, but it increases argument-level nesting and makes the log
harder to read.
9. Performance diagnosis
| Symptom | Measure first | Typical correction |
|---|---|---|
| Long WHILE | attempt count, elapsed time, external latency | smaller domain limit or condition-specific wait |
| Huge output.xml | loop iteration count + per-iteration log volume | reduce unnecessary loop logging after diagnosis |
| CI timeout | Robot loop budget vs CI job budget | make Robot budget intentionally smaller and fail with evidence |
| Parallel contention | which loop iterations mutate shared resource | unique state per test/worker; control flow is not isolation |
10. Intentionally broken diagnostic exercise
Run this only against synthetic local values. It contains two defects: the broad handler hides a permanent failure and the WHILE budget is disconnected from the domain requirement.
*** Test Cases ***
Broken Diagnostic Case
VAR ${attempt} ${0}
WHILE True limit=1000
${attempt}= Evaluate $attempt + 1
TRY
Fail permanent: invalid configuration
EXCEPT AS ${error}
Log retrying after ${error}
END
IF $attempt >= 3 BREAK
END
Repair by removing the broad recovery for
permanent:* and replacing the oversized loop with a
small explicit attempt contract. The repaired test should FAIL
immediately with the permanent message.
11. Troubleshooting shortcuts to reject
limit=NONEin unattended automation.- Catch-all EXCEPT around assertions.
- Turning every failure into a Boolean and continuing.
- Splicing external strings into expressions.
- Retrying without recording the first error and observed state.
- Adding sleeps instead of defining the condition or deadline.
- Deleting output artifacts before diagnosing the original path.
12. Knowledge check
Why is "False" dangerous in IF $value?
It is a non-empty string and therefore truthy in Python. Convert or compare explicitly if the source is textual configuration.
What should a permanent validation error do inside a transient polling loop?
Propagate immediately. Only the explicitly recognized transient failure should authorize another iteration.
Why is BREAK in a helper keyword invalid?
Native BREAK controls the syntactic active loop and must appear in that loop body, though an IF or TRY nested directly in the loop body may contain it.
What should be preserved before changing a broad EXCEPT?
The first failing result artifacts and exact error message, so you can prove what was hidden and verify the repair restores transparent failure semantics.
13. Summary and next step
Control-flow diagnosis starts with the first failing path, not with retries. Bound loops, use object-safe expressions, keep BREAK/CONTINUE in the active loop body, and recover only the failure class your contract actually understands. Lesson 5 combines these rules in a checkpoint state machine with two injected failure classes and a refactoring exercise.
Further reading
- Robot Framework 7.4.2 User Guide — control structures — FOR, WHILE, BREAK/CONTINUE, IF/ELSE, TRY/EXCEPT, and readability guidance.
-
Robot Framework 7.4.2 User Guide — WHILE loops
— expression evaluation, limits,
on_limit, and output-size considerations. -
Robot Framework 7.4.2 User Guide — TRY/EXCEPT
— exact/pattern matching,
AS,ELSE,FINALLY, and uncatchable failures. -
Robot Framework 7.4.2 User Guide — evaluating expressions
—
${var}replacement versus$varaccess and evaluation namespace behavior. - Robot Framework 7.4.2 BuiltIn — legacy-compatible conditional/loop-control helpers and native-syntax recommendations.
- Robot Framework project site — current stable release stream.
Keep the academy open
Support free, practical DevOps education.
Every lesson is designed to remain readable in a browser, downloadable from GitHub, and usable without a paid learning platform. Contributions help expand and maintain the curriculum.
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0
Send only Ethereum/ERC-20 compatible assets to this
address.