Chapter 10Lesson 04190–270 min

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.

DiagnosticsBroken examplesFailure preservationExpression safetyProduction practice

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

  1. Preserve the failing output.xml, log.html, report.html, exact command, and any local trace.
  2. Confirm Robot/Python version and executed suite path.
  3. Validate parse structure: every native block has correct markers and END.
  4. Inspect condition inputs and whether ${var} replacement or $var object access was intended.
  5. Inspect the first failing keyword and exact message before looking at recovery.
  6. Check whether EXCEPT matching, BREAK/CONTINUE, or a loop limit altered the path.
  7. Inspect external state only if the executed keywords actually touched it.
  8. 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=NONE in 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?

What should a permanent validation error do inside a transient polling loop?

Why is BREAK in a helper keyword invalid?

What should be preserved before changing a broad EXCEPT?

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.

Next lesson

Checkpoint Lab — IF/ELSE, FOR, WHILE, TRY/EXCEPT, BREAK, CONTINUE, and Control Flow

Continue with Checkpoint Lab — IF/ELSE, FOR, WHILE, TRY/EXCEPT, BREAK, CONTINUE, and Control Flow. It builds directly on the state, evidence, and operating assumptions established here, so carry those constraints forward rather than treating the next page as an isolated topic.

Further reading

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.

Ethereum / ERC-20
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0 Send only Ethereum/ERC-20 compatible assets to this address.