UIADP common mistakes
UIADP · Understand the traps and how to avoid them.
Inserting a fixed Delay (e.g. 3000 ms) after every click or navigation instead of waiting on the UI element, then declaring the process 'finished' once it happens to work on the developer's machine.
Delay is the most visible activity in the Activities panel and it appears to cure flakiness during development, because the developer's machine is fast and lightly loaded; the real race condition only shows up on a loaded Robot.
What to do instead
Replace fixed waits with state-based synchronisation: 'Check App State', 'Element Exists' or 'On Element Appear' with an explicit timeout, wrapped in a 'Retry Scope' where the UI may lag. Keep a Delay only where the target genuinely exposes no observable UI state, and comment why.
Referencing a variable declared in Main.xaml from inside an invoked workflow, hitting a 'name is not declared' compile error, and 'fixing' it by re-declaring the same variable inside the child workflow.
Variables are scoped to the workflow file that declares them; participants conflate the visual canvas with a single global scope and have not yet internalised the variable-versus-argument distinction.
What to do instead
Pass data across workflow boundaries with arguments (In, Out, In/Out) defined on the invoked workflow and mapped in 'Invoke Workflow File' via Import Arguments. Use the Data Manager to review scope, and 'Extract as Workflow' to move a block together with its dependencies.
Parsing dates and decimals with DateTime.Parse, CDate or a bare ToString(), and reading CSV/Excel text values with the default culture.
String-to-date and string-to-number conversion in .NET is culture-sensitive; it works on the developer's machine because the Robot machine in production runs different regional settings, so the same expression throws or silently swaps day and month.
What to do instead
Use DateTime.ParseExact(text, "dd/MM/yyyy", CultureInfo.InvariantCulture) or TryParseExact when a Boolean result is needed, and format output with ToString("yyyy-MM-dd", CultureInfo.InvariantCulture). Apply the same explicit culture to every number/date conversion and to CSV parsing.
Deleting rows from a DataTable inside a For Each or indexed For loop while still using the original dt.Rows.Count as the loop bound or a fixed row index, producing silently skipped rows and 'There is no row at position N'.
Removing a row shifts every subsequent row index down by one, but the counter was computed against the original count; skipped rows produce no error, so the defect is only discovered when the index finally exceeds the new count.
What to do instead
Iterate backwards (For i = dt.Rows.Count - 1 To 0 Step -1), or use dt.Select("condition") to obtain the rows to remove and delete those, or build a filtered copy with dt.Select(...).CopyToDataTable() instead of mutating the original table.
Keeping the full selector captured by the recorder, complete with volatile attributes such as a session id, a record count in the window title or a generated class name, and then adding idx='1' to force a match.
The selector was captured from one instance of the application where those attributes happened to be stable at that moment; participants do not inspect which attributes actually stay constant across runs and environments.
What to do instead
Open UiExplorer, identify attributes that are genuinely constant (aaname, name, parentid, tag, type), replace volatile fragments with wildcards (*), and inject runtime values as variables in the selector string, e.g. "". Use idx only as a last resort after the attribute set is otherwise stable.
Calling 'Write Range' with AddHeaders enabled inside the loop that processes each transaction item, so the output workbook gains a fresh header row per iteration.
The developer validates with a single item, where the behaviour looks correct, and Write Range without an explicit range also overwrites the sheet, so a re-run hides the duplication.
What to do instead
Write the headers once outside the loop (or seed the file with one initial 'Write Range'), then use 'Append Range' for subsequent iterations, always targeting an explicit starting cell. Verify with a five-item test run and inspect the produced file before publishing.
Wrapping the entire Process Transaction body in a Try/Catch that catches System.Exception and only logs 'Error occurred', then letting the loop continue as though the transaction succeeded.
Participants add Try/Catch defensively to make the popup and the debugger stop, treating an exception as something to suppress rather than something to classify and route.
What to do instead
Catch BusinessRuleException separately from System.Exception, log Exception.Message plus Exception.Source and the transaction identifier, and set the transaction status accordingly. Use 'Rethrow' when the calling framework must decide, so failures surface in Orchestrator instead of being swallowed.
Publishing a package with 'Publish to Orchestrator' and assuming the change is live, without upgrading the Process to the new package version or checking the robot user's folder access and machine template.
Orchestrator pins each Process to a specific package version and modern folders grant access per user and folder, so 'the package uploaded' is easily mistaken for 'the process was updated and can run'.
What to do instead
After publishing, confirm the version under Tenant > Packages, create or upgrade the Process version in the target folder, verify the user/robot folder assignment and machine template, then read the job's Info and Error logs in Orchestrator rather than re-publishing.
In REFramework, doing the per-transaction work but leaving TransactionStatus unset, or setting it to Success before the work executes, or catching a BusinessRuleException and marking it as a system error so the item is retried indefinitely.
The framework drives its state machine from io_TransactionItem, TransactionStatus and the retry counters; a wrong status sends control back to Get Transaction Data and the same item loops instead of advancing.
What to do instead
Set TransactionStatus = Success only after the transaction work completes, set BusinessRuleException for deterministic rule violations (no framework retry), and let SystemException drive the retry path. Test with a queue containing one valid, one business-rule and one system-error item.
Committing the entire project folder including bin/, obj/, .local/ and the downloaded packages, while two developers edit Main.xaml and project.json in parallel branches.
Studio regenerates those folders and rewrites project.json automatically whenever a variable or argument changes, so parallel edits produce conflicts that cannot be meaningfully hand-merged, and generated binaries bloat the repository.
What to do instead
Use the Studio Git integration with a .gitignore covering bin/, obj/, .local/ and packages; commit project.json and the .xaml files only, pull before starting work, keep changes small and isolated to separate workflows, and resolve project.json conflicts by regenerating it in Studio rather than merging by hand.