Troubleshooting
Start with the doctor. It checks the toolchain, the simulator runtimes, the device tunnel, WebDriverAgent’s build and signing, the devices and the model, and gives a remedy for each failure:
uv run ios-agent doctor # or: uv run ios-mcp doctor12 ok. Ready to automate: simulator, real device.
[PASS] xcode: Xcode 27.0 at /Applications/Xcode.app/Contents/Developer [PASS] simulators: 11 simulator(s) on iOS 27.0 [PASS] wda-bundle: simulator bundle ready, device runner ready [PASS] model: openai:gpt-5.6-sol ...The terminal app runs the same checks before it touches a device, so a Mac that is not set up is told so in about a second rather than after a simulator has booted. If the doctor passes and something still fails, find the symptom below.
Setting up
Section titled “Setting up”| Symptom | Cause and fix |
|---|---|
xcode fails |
Only the Command Line Tools are installed. Install the full Xcode, then sudo xcode-select -s /Applications/Xcode.app. |
simulators fails: no runtime |
Xcode ships without one. xcodebuild -downloadPlatform iOS, about 8 GB. |
simulators fails: a runtime but no device |
ios-agent offers to create one, which takes under a second; or xcrun simctl create. |
wda-bundle fails |
WebDriverAgent is not built. ios-mcp prepare-wda simulator builds it in about 20 seconds, into the directory the remedy names; ios-agent quickstart offers the same. In a clone, ./scripts/prepare_wda.sh simulator still works. |
model warns |
No credential this project can see. Bedrock, Vertex and an ant auth login profile resolve their own, so a warning is not always a problem. manual mode needs no model at all. See Choose a model. |
| The simulator runs but no window appears | Expected with IOS_MCP_SIMULATOR__SHOW_WINDOW=false. On Xcode 27 the window is Device Hub, not Simulator.app; automation does not need it either way. |
A run that stalls or times out
Section titled “A run that stalls or times out”| Symptom | Cause and fix |
|---|---|
| The first run after a crash times out waiting for WebDriverAgent | A runner is still holding the device. Runners stop with the process that started them, even when it is killed, so this one was started some other way. uv run ios-mcp reset lists it and -y stops it. |
| One call blocks for about a minute after leaving an app | The first snapshot after an app is backgrounded waits 61 seconds on the app that went away. home avoids it; another route to the home screen may not. See device realities. |
| Every action on a phone takes 8 to 12 seconds | Normal: a tree read costs seconds on a phone against under one on a simulator. IOS_MCP_STABILIZE__SIGNAL=frames settles on screenshots instead, 17 to 22% faster on a phone (ADR 0019). |
session_halted |
The gate stopped the session: five failed actions in a row, or the screen cycling between the same few states. Read the reason in ios_session_status, then ios_resume. |
A physical iPhone
Section titled “A physical iPhone”| Symptom | Cause and fix |
|---|---|
| The phone is not listed | Unlock it, tap Trust, and turn on Developer Mode under Privacy & Security. ios-agent devices says what is missing for each device. |
tunnel_down |
No tunnel, and none could be started. Unlock the phone and check the cable, or run ios tunnel start --userspace. |
device_locked |
The phone slept. A session wakes it but cannot type a passcode; set Auto-Lock to Never for long runs. |
Works for a week, then signing_invalid |
A free Apple ID’s profile lasts seven days. Re-run ./scripts/prepare_wda.sh device. A profile reissued after it expired asks for Trust on the phone again, and may need TEAM_ID passed explicitly. |
ApplicationVerificationFailed on install |
The runner bundle was changed after it was signed. Rebuild it rather than editing it. |
Launch fails with deviceprocesscontrolservice code 2 |
The developer certificate is not trusted on the phone: Settings, General, VPN & Device Management. |
The full device walkthrough is Use a physical iPhone.
What the agent sees
Section titled “What the agent sees”| Symptom | Cause and fix |
|---|---|
| A screen comes back nearly empty | Flutter canvases and WebViews have no accessibility tree. The digest carries a note saying so; use ios_screenshot for that screen. ADR 0007 |
element_not_found for something visible |
The digest dropped it to stay within budget, or it has no label. ios_find searches the full tree; ios_screenshot(annotate_refs=true) shows every ref on the picture. |
element_stale or element_ambiguous |
The screen moved since the agent looked. The error lists the closest candidates; observe again and act on a current ref. |
Typed text comes back ok: false with text_mismatch |
The field holds something other than what was typed, which the read-back caught. The typed entry says what it holds. |
action_requires_approval |
The gate is asking. See Approvals and secrets. |
Every error carries a code, a hint and often details; the codes are
listed in the tool reference.