Unknown outcomes
What action_outcome_unknown means, why Phonebox never retries a write for you, and how to observe and decide what to do next.
action_outcome_unknown means Phonebox sent a write to the phone, such as a tap, typing or an install, and the phone didn't confirm it. The request may have timed out, or the phone's connection broke off after the write could already have reached it. The action may have happened, partly happened, or not happened at all. Its retryable is always false.
Where it appears
- In an action's result. The batch stops at that action, and the actions after it don't run. The response includes the element list of the screen, unless reading the screen after the batch failed or ran out of time.
- As the error of a whole request that writes to the phone: installing or uninstalling an app, uploading or deleting a file, setting the clipboard, setting or resetting the location, setting the locale or the timezone, and rebooting. These answer
502 action_outcome_unknown.
A partial action is a related case. A type with submit and a double_tap each take two steps, and when the second step fails after the first reached the phone, the result has details.partial set to true and retryable set to false, whatever its code. The first step happened, and the second may or may not have.
Why nothing is retried for you
Phonebox sends every write to the phone once and never repeats it, and the SDK and the CLI don't either. A repeated tap on "Pay" can pay twice, a repeated "Send" can send a message twice, and a repeated reboot restarts a phone that may already be restarting. Only you can tell from the screen whether the first attempt worked.
Reads are different, because repeating them changes nothing: Phonebox retries its own reads of the phone for up to about 15 seconds. And when Phonebox's own error says that nothing ran, such as a retryable 503 phone_unavailable in its error envelope, the write never reached the phone, so sending it again is safe.
Observe, then decide
- Observe. Read the screen, with a screenshot when the element list might not show the change:
GET /v1/phones/{id}/observe?screenshot=jpeg&max_width=720. If the phone was rebooting, wait for it withGET /v1/phones/{id}?wait=readyfirst. - Compare. Work out what the action should have changed. Look for the next screen, the text in the field, the item in the cart, or the message in the conversation.
- Decide.
- If it happened, carry on with the next step, as if the action had succeeded.
- If it clearly didn't happen, send it again, once.
- If you can't tell, don't guess. Check in a way that is safe to repeat, such as a
wait_foron the text that would confirm it, or ask your user, handing the phone over with a live view link when a person should look.
For a partial action, observe in the same way, and never send the second step blindly. For a type with submit, send a key action for enter only when the screen still shows your text in the field and hasn't moved on. For a double_tap, check whether the second tap is still needed before you tap again.
Checks for requests that write
| Request | How to check whether it happened |
|---|---|
| Install an app | List the installs, or the installed apps. |
| Uninstall an app | List the apps. |
| Upload or delete a file | List the directory. |
| Set the clipboard | Read it back. |
| Set or reset the location, or set the locale or timezone | These settings can't be read back, but sending the same value again leaves the phone as you meant it. A locale change restarts the interface each time, so observe afterwards. |
| Reboot | Wait with GET /v1/phones/{id}?wait=ready, as the error's next says. Never send a second reboot to find out whether the first one worked. |
When no answer comes from Phonebox
A timeout or a dropped connection on your side hides the outcome in the same way, even when Phonebox finished the request. So does a 502 or 504 whose body isn't Phonebox's error envelope, which a proxy, a load balancer or the hosting platform sends, for example when a request runs past its time limit. None of these says whether anything ran. Treat them by what the request does:
- Create. Send it again with the same
Idempotency-Keyand body. You get the phone the first request created, if it did, and never a second one. If that phone has failed or was deleted, create the next one with a new key. Without a key, list your phones before you create another. - Park and heartbeat. Send them again. They are safe to repeat.
- Start. Read the phone first, with
GET /v1/phones/{id}. A start on a running phone renews its session and reserves credit again, so start it again only while it is stillparkedorunavailable. If it isstartingorready, it is running: wait withGET /v1/phones/{id}?wait=readyinstead. - An action batch. Observe first, as above. Give batch requests a client timeout of about 300 seconds, so that a long batch isn't cut off on your side.
- Other writes. Check whether they happened, with the checks above, before you send them again.
- Reads. Send them again.