Most failures fall into a few families: a desktop control the Robot could not address, a suite that reported red for a reason that is not the automation, a generation gate that refused, or a licence or credential check that refused before any work started. Each leaves a record and a next step.
#Start with the run record
The Robot's exit code is machine-consumable:
0the run finished, successfully or completed-with-errors. The Robot did its job.2the run failed fatally (system or init failure).3the run was stopped by the operator.1a usage or configuration error.
The run's diagnostics report is built from what the run recorded. It has a headline sentence, then one entry per failed transaction with the outcome, the attempt count, the named code, the error message verbatim and, when the automation named its steps, the step that failed. A code the platform emits today has a repair hint; a code it does not gets none, rather than invented advice.
npx tsx robot/cli.ts show process-invoices <runId>
Look at the evidence directory too: state.json, logs.txt and summary.json are the run's own account.
#Desktop failures
Each desktop refusal carries a code that says what to do.
DESKTOP_TARGET_NOT_FOUND: the window was found and the control was not in it. The application is in a different state, or a different version. Bring it to the state the step expects and re-prove:desktop bind <declared>.DESKTOP_TARGET_NOT_RENDERED: the control exists but is not in the accessibility tree yet. A tab that is not active or a panel not yet opened is a state prerequisite, not a broken locator.DESKTOP_MULTIPLE_MATCHES: the locator matched more than one control, so nothing was touched. Tighten the declaration with a scope or an anchor relation, then re-prove it.DESKTOP_UIA_UNAVAILABLE: no accessibility bridge is reachable. Run on an interactive desktop session. This is an environment fault.DESKTOP_SESSION_INTERACTIVE_REQUIRED: the session is not interactive. An unattended robot needs a logged-in desktop for this capability.DESKTOP_APP_NOT_RUNNING: the application the step needs is not running. Start it in the process, or move the step after whatever starts it.DESKTOP_SET_VALUE_UNSUPPORTEDandVALUE_NOT_ACCEPTED: the control cannot be written to, or accepted the call and did not change. Declare what the control actually is, or drive the change where the application performs it.NOT_SELECTABLE: the option was found and could not be selected. Re-record the choice against the open control.
#Suite failures
A red suite is usually one of four things.
A stale target override in the launching shell was the cause of the first scheduled smoke coming back red with a connection refused. The runner now strips TS_TARGET_URL, TS_DEMO_URL and TS_DATA_DIR from the child environment unless the test declares them in params. The runner records the overrides it stripped and the params it applied, on passes and failures alike.
A missing credential fails the test by name rather than running without it.
A test that exceeds its timeoutMs is killed and failed, with the message naming the budget. A suite that reaches its maxDurationMs marks tests that never started as cancelled, which is not the same as failed: "we stopped asking" is its own outcome.
An --only run records every test it did not cover as skipped with the reason, so a green subset never means everything was checked.
npx tsx orchestrator/cli.ts suite result <suiteRunId>
#Generator and licence refusals
A generation that fails a gate stops there. The gate names the fault: parse, schema, bind, lint, typecheck, test or package. With --remote the run repairs itself up to twice from structured diagnostics. Binding refusals are named: REFUSED_BINDING_WITHOUT_INTENTS, REFUSED_UNPROVEN_TARGETS_FILE, REFUSED_INTENTS_UNPROVEN and the accounting codes. The run writes nothing on a refusal.
Licence refusals stop a run before any step exists. LICENCE_MISSING means the deployment declared itself licensed and could not prove it. LICENCE_EXPIRED means the lease and its grace have ended; renew through the platform. LICENCE_SIGNATURE_INVALID means the lease was not issued by this platform or was altered after issue. None of these is retryable, because they are not the automation's failure.
#Storage and backup errors
state-backup.mjs fails closed when the state root holds key material, naming the files, because a whole-root copy would put the key beside the ciphertext. Pass --exclude-key-material, or move the key out of the root. A restore refuses a backup target directory and names the stamp to use. A restored encrypted vault will not open until the wrapping key is supplied; vault doctor reports the vault form and the key location it actually used.