Chapter 06Lesson 04150–200 min

Variables: Scalar, List, Dictionary, Environment, and Dynamic Values: Diagnostics, Failure Modes, and Production Practices

Diagnose variable failures by preserving evidence, separating source/priority/scope/type problems, and repairing the smallest ownership boundary instead of adding globals or retries.

DiagnosticsShadowingMutationSecretsFailure analysis

Learning objectives

  • Classify a variable incident as resolution, scope, type, mutation, path, environment, or secret-handling failure.
  • Preserve first-failure output before changing values or rerunning a suite.
  • Diagnose shadowing and static priority using explicit source evidence rather than guesswork.
  • Repair shared mutable state without masking the failure through retries or global variables.
  • Recognize when a Secret value can still leak through explicit unwrapping or external tools.

Current compatibility baseline. Verified 2026-08-31: Robot Framework 7.4.2 is the stable release used by this chapter and requires Python 3.8+. Robot Framework 7.5b1 is a pre-release and is not required. Native VAR has existed since 7.0; scope=SUITES since 7.1; variable type conversion such as ${count: int} is stable since 7.3; and Secret variables are stable since 7.4.

1. Diagnostic sequence

When a variable-related test fails, preserve the original output.xml, log.html, console command, and non-sensitive environment/profile evidence. Then diagnose in this order:

  1. Confirm Robot/Python versions and exact executed path.
  2. Confirm command-line variables and variable files supplied at startup.
  3. Inspect imports and Variable sections.
  4. Inspect local/test/suite/global runtime definitions and shadowing.
  5. Confirm object type and whether a container is shared.
  6. Inspect external environment/secret source without printing real secrets.
  7. Only after variable resolution is proven, investigate downstream library/system state.

This sequence avoids blaming a browser/API/database when the wrong value never reached that layer.

2. Failure mode: shadowing looks like overwrite

Suppose a suite default says ${REGION}=eu-west but one keyword receives an argument named ${region}. Inside the keyword the local argument wins. After the keyword returns, the suite value is still intact. Logging only one layer can create the false impression that the suite variable changed.

*** Variables ***
${REGION}    eu-west

*** Test Cases ***
Shadowing Example
    Report Region    us-east
    Should Be Equal    ${REGION}    eu-west

*** Keywords ***
Report Region
    [Arguments]    ${region}
    Should Be Equal    ${region}    us-east

Repair is often naming/context clarity, not Set Global Variable.

3. Failure mode: startup priority surprise

A CI wrapper may provide -v STAGE:staging while the suite file says ${STAGE}=local. Editing the suite file will not change the effective value because the higher-priority command-line source still wins.

python -m robot --variable STAGE:staging --outputdir results/failure suites/

Preserve the exact invocation in the evidence packet. Configuration provenance is part of the test result.

4. Failure mode: numeric-looking strings

Environment variables are strings. The value "10" can look numeric in a log but behave differently in comparisons, arithmetic, or library type conversion. The repair is to establish a typed boundary rather than scatter ad-hoc conversions through keywords.

*** Test Cases ***
Broken Type Assumption
    VAR    ${workers}    %{RF_WORKERS=10}
    # ${workers} is a string here.

Repaired Boundary
    VAR    ${workers: int}    %{RF_WORKERS=10}
    Should Be True    $workers >= 1

5. Failure mode: shared list mutation contaminates the next test

This is the chapter’s intentionally broken case. A suite-scoped list is mutated by the first test. The second test expects the original baseline and fails. Retrying the second test or increasing a timeout cannot repair the ownership bug.

*** Settings ***
Library    Collections

*** Variables ***
@{BASE_ITEMS}    alpha    beta

*** Test Cases ***
Test A Mutates Shared State
    Append To List    ${BASE_ITEMS}    gamma
    Should Contain    ${BASE_ITEMS}    gamma

Test B Expects Baseline
    Should Be Equal    ${BASE_ITEMS}    ${{['alpha', 'beta']}}

Expected failure: Test B sees gamma. The diagnostic evidence is the first test’s mutation plus the suite-owned container identity/lifetime.

Repair: keep an immutable/static baseline and copy it locally per test before mutation.

*** Test Cases ***
Isolated Test
    ${items}=    Copy List    ${BASE_ITEMS}
    Append To List    ${items}    gamma
    Should Be Equal    ${BASE_ITEMS}    ${{['alpha', 'beta']}}

6. Failure mode: variable file depends on the working directory

A relative --variablefile config/dev.py resolves from the process invocation context. A local run from project root may pass while CI starts in another directory. Diagnose the executed working directory and command before adding arbitrary PYTHONPATH hacks.

Prefer a documented project-root invocation or file-relative import conventions. The variable source should be reproducible from the same entry point used by CI.

7. Failure mode: treating Secret as encryption

A Secret can still leak when code deliberately accesses .value, when a library unwraps it and logs the plain value, or when another process receives it without compatible redaction. Avoid TRACE-level diagnostics for sensitive paths unless you know the complete logging chain.

*** Variables ***
${TOKEN: Secret}    %{RF_TOKEN=FAKE_ONLY}

*** Test Cases ***
Unsafe Debugging Pattern
    # Do not do this with real secrets:
    # Log    ${TOKEN.value}

The production repair is not “mask the screenshot later.” Keep acquisition, transport, library compatibility, result retention, and redaction as separate controls.

8. Performance: variables are rarely the first bottleneck

Variable parsing and lookup are usually negligible compared with browser/API/database calls. Large dynamic variable files can add import/setup cost, and enormous logged structures can inflate output.xml, but measure before tuning. Do not replace clear scoped values with global caches unless evidence shows a real bottleneck and the state semantics remain correct.

9. Knowledge check

Why will editing a suite Variable section not override -v STAGE:staging?

Why is retrying Test B in the shared-list example a bad fix?

What evidence should be preserved before changing a variable incident?

Can a Secret-aware Robot log protect a value that an external library prints after unwrapping it?

10. Summary and next step

Variable diagnosis starts with provenance and lifetime. Static priority, runtime shadowing, type conversion, mutable-object aliasing, working-directory assumptions, and secret handling each fail differently. Lesson 5 combines them in a checkpoint where you predict winners, verify them, and repair a shared-state bug while preserving evidence.

Next lesson

Checkpoint Lab — Variables: Scalar, List, Dictionary, Environment, and Dynamic Values

Continue with Checkpoint Lab — Variables: Scalar, List, Dictionary, Environment, and Dynamic Values. 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.