Resource library

QA How-To

How to Fix Appium "socket hang up"

Fix Appium socket hang up errors by tracing client, Android UiAutomator2, and iOS WebDriverAgent connections with commands that verify each repair in CI.

17 min read | 3,202 words

TL;DR

Find which connection closed: client to Appium, Appium to UiAutomator2, or Appium to WebDriverAgent. Confirm the server, device transport, helper process, and forwarding port in that order, then rerun the failing command.

Key Takeaways

  • Probe Appium /status from the same runner that executes the test.
  • Use the server log to locate whether the reset occurred before or after a proxied device request.
  • Check Android ADB transport and UiAutomator2 instrumentation before adjusting timeouts.
  • Inspect Xcode output and WebDriverAgent status for iOS startup failures.
  • Allocate unique forwarding ports and devices to parallel workers.
  • Verify the repair with a real session command and the original failing action.

If you need to fix Appium socket hang up during session creation or while a command runs, first find which connection closed: test client to Appium, Appium to UiAutomator2 on Android, or Appium to WebDriverAgent on iOS. The same short message can describe three different failures.

Could not proxy command to the remote server. Original error: socket hang up

Keep the Appium server log, device log, and the failing request together. A retry may make the symptom disappear while leaving the underlying device, port, or helper-process problem intact. The checks below move from the outside of the connection toward the device, so you can stop as soon as one boundary fails.

TL;DR

  1. Run curl -fsS http://127.0.0.1:4723/status on the machine that runs the test. If it fails, fix the server address, port, container mapping, or server process before touching the device.
  2. Start Appium with appium --log-level debug, repeat one failing command, and locate the last successful proxy request. On Android, check adb devices -l and appium driver doctor uiautomator2. On iOS, enable appium:showXcodeLog and check whether WebDriverAgent is listening.
  3. If parallel sessions fail but a single session passes, assign each Android session a distinct appium:systemPort or each real-device iOS session a distinct appium:wdaLocalPort.
  4. Change timeouts only after you see a slow but living downstream service. A process that crashed or an occupied port will not recover because you waited longer.

What the Error Actually Means

A socket is a transport connection. "Socket hang up" means the peer closed it before the HTTP exchange completed. It is not a diagnosis of the app under test, nor proof that Appium itself crashed. Appium may receive your WebDriver request successfully, then lose its separate HTTP connection to the automation server on the device. A Java client may wrap that event in a WebDriverException; a JavaScript client may expose a connection reset. The informative line is often several log entries earlier.

Treat the path as three boundaries: client to Appium, Appium to host-side forwarding, and forwarding to the device helper. The Appium server CLI reference documents server options, while the UiAutomator2 driver capabilities and XCUITest capabilities describe the two downstream links. Capture a timestamp and session ID before changing configuration. If the server never logs your request, investigate the client boundary. If it logs a proxied request and then the reset, investigate the helper.

A clean /status response proves that the Appium HTTP listener answers. It does not prove that Android instrumentation or iOS WebDriverAgent is healthy. Conversely, an offline device can leave the listener healthy while every session command fails. Keep these facts separate during triage. For a larger setup walkthrough, see the Appium mobile automation guide.

Root-Cause Decision Table

Symptom Likely root cause First fix and proof
No Appium request appears in the server log Wrong host, port, base path, or dead listener Query the exact /status URL from the test runner
adb devices -l says offline or omits the target USB, emulator, or ADB transport lost Restore the device to device state and run an ADB shell command
Appium proxies to UiAutomator2, then resets Android instrumentation exited or installed helper is stale Read logcat, remove stale helper packages if indicated, start a new session
One test passes, parallel tests fail Host-side forwarding port collision Give each worker a distinct systemPort or wdaLocalPort
Xcode log shows WDA build or launch failure Signing, trust, or WDA startup problem Fix Xcode failure, then query the WDA status endpoint
Reset occurs after a long, expensive command Downstream response exceeded a configured time limit Measure duration and adjust the relevant read timeout only
Local passes, CI or Docker fails Runner cannot reach server or device bridge Probe status and device visibility inside the runner environment
Failure follows an Appium or driver update Incompatible or missing extension in the active APPIUM_HOME List installed drivers, run doctor, and retest one session

1. Fix Appium Socket Hang Up at the Client-to-Server Boundary

Start on the test runner, not in a browser on your laptop if the test runs elsewhere. Compare the host, port, and base path used by the client with the Appium startup banner. Modern Appium defaults to the root path; a legacy client aimed at /wd/hub needs that path configured deliberately. A wrong path normally produces an HTTP routing error rather than a socket reset, but wrappers and proxies can obscure the original response. For a fixed legacy path, start Appium with --base-path /wd/hub and probe /wd/hub/status. Check the actual route before diagnosing device internals.

In one terminal, start a foreground server. In another, request its status and inspect the listening process. If you already run a managed server, keep it running and use its configured address instead of starting a duplicate.

appium --address 127.0.0.1 --port 4723 --log-level debug
curl -i --max-time 5 http://127.0.0.1:4723/status
lsof -nP -iTCP:4723 -sTCP:LISTEN

The verification is an HTTP success with a JSON status response and a listener owned by the process you intended. A refused connection means the server is down or bound elsewhere. If curl works but the test fails, compare the URL printed by the client and look for the request in Appium's debug log. For remote runners, 127.0.0.1 means the runner itself, not your workstation. Configure a reachable address and restrict access appropriately.

2. Restore an Android Device That ADB Lost

An Android session relies on ADB even after Appium has started. A loose USB cable, a sleeping emulator, revoked USB debugging authorization, or competing ADB installations can interrupt the forwarding channel. The server may still accept requests while a proxied device command resets. Begin by checking exactly which target the runner sees.

adb devices -l
adb shell getprop sys.boot_completed
adb shell echo transport-ok

Run those commands with one attached target. With multiple targets, add -s <device-serial> to each adb invocation using a serial from adb devices -l. The verification is a row in device state, a boot-complete value of 1, and transport-ok from the shell. An unauthorized row requires accepting the debugging prompt on the device. An offline row calls for reconnecting the cable or restarting the emulator, then rerunning the same probe.

Check whether the forwarding rule exists only after a session has started, because Appium creates it for UiAutomator2. Do not assume a remembered port belongs to the current device.

adb forward --list

The list should include a TCP mapping associated with your target during an active session. If ADB cannot run a trivial shell command, changing Appium read timeouts cannot repair it. If the transport becomes unreliable only in CI, preserve adb devices -l output from both before and after the failing test. The Appium Android setup guide covers SDK and device prerequisites; the mobile device farm guide is useful when device assignment is remote.

3. Restart UiAutomator2 After an Instrumentation Failure

On Android, Appium forwards native automation commands to a UiAutomator2 server installed on the device. A reset immediately after "Proxying" points to that service, its instrumentation process, or the ADB forward. Inspect the first fatal log line, not only the final "socket hang up". Android can kill instrumentation under memory pressure, an incompatible helper can fail at startup, or a device-specific permission can block it.

adb logcat -d -v time | grep -E 'FATAL EXCEPTION|AndroidRuntime|io.appium.uiautomator2|INSTRUMENTATION' | tail -n 100
adb shell pm list packages | grep io.appium.uiautomator2

The first command verifies whether the device logged an instrumentation crash near the test timestamp. The second shows whether the helper packages are installed. If logs implicate stale or broken UiAutomator2 packages, stop the session, uninstall only those helper packages, and let the driver reinstall them on the next session. This removes helper state, not your app under test.

adb uninstall io.appium.uiautomator2.server
adb uninstall io.appium.uiautomator2.server.test
appium driver doctor uiautomator2

An adb uninstall result of Success means a package was removed; a package-not-installed result simply means there was nothing to remove. The doctor command should report no required fixes. Start a new session and verify the helper packages reappear with adb shell pm list packages | grep io.appium.uiautomator2. Avoid appium:skipServerInstallation: true while repairing this problem: the driver documentation warns that a missing or mismatched helper can fail later when that shortcut is used. The driver installation tutorial explains host-side driver installation, which is distinct from device-side helper APKs.

4. Fix Appium Socket Hang Up in Parallel Sessions

Parallel sessions require isolated host ports and distinct devices. For Android, appium:systemPort identifies the host port forwarded to one device's UiAutomator2 server. For real iOS devices, appium:wdaLocalPort identifies the Mac-side WDA forwarding port. If two workers select the same local port, one can reach the other's session or fail when forwarding starts. A single-worker pass followed by a parallel failure is strong evidence to test this hypothesis.

Choose an unused port per worker, then pass it as a W3C vendor-prefixed capability. These JSON fragments are complete session payloads for direct HTTP checks once their device serials are replaced with actual values. Use values from your own port allocation plan, and keep the device assignments stable for the duration of each session.

{
  "capabilities": {
    "alwaysMatch": {
      "platformName": "Android",
      "appium:automationName": "UiAutomator2",
      "appium:deviceName": "Android",
      "appium:udid": "YOUR_FIRST_DEVICE_SERIAL",
      "appium:systemPort": 8201
    },
    "firstMatch": [{}]
  }
}
{
  "capabilities": {
    "alwaysMatch": {
      "platformName": "iOS",
      "appium:automationName": "XCUITest",
      "appium:deviceName": "iPhone",
      "appium:udid": "YOUR_SECOND_DEVICE_UDID",
      "appium:wdaLocalPort": 8101
    },
    "firstMatch": [{}]
  }
}

Save the appropriate payload as session.json and verify one worker with curl -fsS -H 'Content-Type: application/json' --data @session.json http://127.0.0.1:4723/session. A successful response contains a sessionId; delete that session through your client after the check. Next run two workers and inspect lsof -nP -iTCP:8201 -sTCP:LISTEN or the corresponding WDA port on macOS. The Appium parallel testing guide covers worker-to-device assignment. Never solve a collision by changing every worker to the same new port.

5. Repair WebDriverAgent on iOS

XCUITest commands pass through WebDriverAgent (WDA). A reset while Appium checks WDA status can mean WDA never launched, crashed, or cannot be reached through its local port. Inspect the Xcode output before raising a timeout. Real devices must have a trusted, correctly signed WDA runner. A failed build or provisioning error is a different repair from a live WDA that responds slowly.

Confirm the active Xcode selection and device visibility on the Mac that runs Appium. Then enable Xcode logging in the test capabilities and create one session. The capability is documented by the XCUITest driver.

xcode-select -p
xcrun simctl list devices booted
appium driver doctor xcuitest

For a simulator, a booted device should appear in the second command. For a real device, inspect it in Xcode's Devices and Simulators window and confirm the WDA signing team and trust state. The doctor command verifies host prerequisites; it cannot approve a device trust prompt for you. Add the following capability to the iOS session payload used in the previous section, then read the Xcode lines that precede the reset.

{
  "appium:showXcodeLog": true
}

This is a capability addition, not a separate session payload. After WDA launches, query its forwarded status URL from the same Mac: curl -i --max-time 5 http://127.0.0.1:8100/status, replacing the port if wdaLocalPort differs. An HTTP response shows that forwarding reaches WDA. If xcodebuild reports signing failure, fix signing first. If WDA runs but the local port is occupied, allocate a unique port as in section 4. The iOS driver setup tutorial covers WDA preparation in more detail.

6. Distinguish a Slow Command From a Dead Helper

A timeout and a reset can occur near each other, but they are not interchangeable. Before changing limits, record the duration of the last proxied command and check whether the downstream service remains alive. If a source lookup on a large screen takes longer than the configured read timeout, the correct setting is the Android appium:uiautomator2ServerReadTimeout or iOS appium:wdaConnectionTimeout, both measured in milliseconds. The client library can also have its own request timeout.

Create a minimal Android smoke test with the official Appium-recommended WebdriverIO client. The script opens a session on one connected device, requests source, and always deletes the session. The source request is deliberate: it tests an actual proxied command after session creation. Install webdriverio in a scratch Node project if your framework does not already have it.

npm init -y
npm install --save-dev webdriverio
adb devices -l

Save this as smoke.cjs. Set ANDROID_UDID to the connected serial, APPIUM_HOST to the reachable server host if it is remote, and APPIUM_PATH only if you changed Appium's base path.

const { remote } = require('webdriverio');

async function main() {
  if (!process.env.ANDROID_UDID) {
    throw new Error('Set ANDROID_UDID from adb devices -l');
  }
  const driver = await remote({
    hostname: process.env.APPIUM_HOST || '127.0.0.1',
    port: Number(process.env.APPIUM_PORT || 4723),
    path: process.env.APPIUM_PATH || '/',
    capabilities: {
      platformName: 'Android',
      'appium:automationName': 'UiAutomator2',
      'appium:deviceName': 'Android',
      'appium:udid': process.env.ANDROID_UDID
    }
  });
  try {
    const source = await driver.getPageSource();
    console.log('Page source characters:', source.length);
  } finally {
    await driver.deleteSession();
  }
}

main().catch(error => {
  console.error(error);
  process.exitCode = 1;
});

Verify with ANDROID_UDID=YOUR_DEVICE_SERIAL node smoke.cjs. Expect a positive character count and a clean session deletion. Repeat the same command after adding one measured timeout capability to the capabilities object, for example 'appium:uiautomator2ServerReadTimeout': 300000 for Android. That value is an illustrative five-minute ceiling, not a universal recommendation. If the failure remains immediate or logcat shows process death, revert the timeout change and repair the helper. See Appium wait strategies for element waits, which solve a different problem from transport timeouts.

7. Reproduce the Failure From CI or Docker

A container's loopback address belongs to the container. If Appium runs on the host, localhost:4723 inside the test container is the wrong endpoint unless you set up a network path. Similarly, an Android emulator attached to the host does not automatically appear inside a Linux container's ADB environment. This explains why a local smoke test passes while the CI worker reports a reset or cannot create a session.

First run these probes in the same job or container that runs the test, using the host name configured for that environment:

curl -i --max-time 5 "http://$APPIUM_HOST:4723/status"
adb devices -l

The first must return Appium's status response. The second must show the target in device state if Android automation runs there. If either fails, repair network routing or ADB access before changing test code. On Linux Docker Engine, a host-running Appium can be exposed with a host gateway mapping when your runner permits it:

docker run --rm --add-host=host.docker.internal:host-gateway   -e APPIUM_HOST=host.docker.internal   'curlimages/curl:<your-approved-tag>'   -fsS http://host.docker.internal:4723/status

For this probe, Appium must listen on an interface reachable from Docker, rather than only 127.0.0.1; secure that listener on your CI network. Replace the image tag placeholder with the approved curl image version used by your CI policy for reproducible jobs. The command verifies HTTP reachability only, not ADB passthrough. If Appium runs in its own container, place the client container on the same Docker network and use the Appium container's service name; publish the Appium port only when a process outside that network needs it. The CI troubleshooting questions include the distinction between service health and runner connectivity.

8. Align the Appium Driver With the Active Installation

Appium drivers are extensions. An updated server process may use a different APPIUM_HOME than the shell where you installed a driver. A missing or incompatible driver generally produces a clearer session-creation error, but deployment scripts can bury it under a generic client connection failure. Inspect the active installation before deleting caches or reinstalling the entire toolchain.

appium --version
appium driver list --installed
appium driver doctor uiautomator2

For iOS, replace the final command with appium driver doctor xcuitest. The verification is that the required driver appears in the installed list and doctor reports no required host fixes. Restart the Appium server after changing extensions, then repeat the one-device smoke test. If a driver is absent, install the named extension with appium driver install uiautomator2 or appium driver install xcuitest while the server is stopped. Match extension versions to the Appium version actually deployed; do not copy an arbitrary version pin from another project.

How to Verify the Fix

Run the smallest test that crossed the failed boundary. A healthy status endpoint alone is insufficient. On Android, use ANDROID_UDID=YOUR_DEVICE_SERIAL node smoke.cjs from section 6, then repeat the original command that failed. On iOS, create a session on the target device, request page source through your client, and close the session. Watch the Appium log for a completed proxied response rather than a reset. Keep the server debug log from both the failed and successful runs so the changed behavior is observable.

For intermittent failures, repeat the smoke test on the same device and worker assignment that previously failed. Record the session ID, device serial or UDID, Appium process, and host forwarding port for each run. A pass on a different simulator does not verify a fix for a real-device signing problem. A pass with one worker does not verify a parallel port fix. Include a run after the device or CI job restarts, because stale forwarding and helper state often reappear at that boundary.

Prevent It From Coming Back

Keep Appium's debug log and platform logs as CI artifacts when a mobile job fails. For Android, capture adb devices -l, relevant logcat, and the driver list. For iOS, capture Xcode output when WDA launch fails and note the device UDID and selected Xcode path. These artifacts let the next engineer tell a dead helper from a slow command without rerunning the entire pipeline.

Allocate one device and one forwarding port per worker. Centralize the mapping in the runner configuration instead of letting each test invent a port. On Android, avoid skipServerInstallation unless the device image and driver helper are deliberately kept in sync. On iOS, keep WDA signing and trust as part of device provisioning. Check /status and device visibility before starting the suite, and fail early with the failing boundary named.

Interview Questions and Answers

Q: What does "socket hang up" tell you in an Appium log? It tells you a transport connection closed before the HTTP exchange finished. Locate the source and destination of that connection before assigning blame to the test or app.

Q: Why can /status pass while the session still fails? The endpoint checks Appium's HTTP listener. Android UiAutomator2 and iOS WebDriverAgent are separate services reached later in the session.

Q: What is the first Android command you run? adb devices -l establishes whether the runner sees the intended device in device state. Then an adb shell probe checks that the transport actually carries commands.

Q: When would you remove UiAutomator2 helper packages? Only after logs suggest stale or broken device-side instrumentation. Remove the two io.appium.uiautomator2 packages, restart the session, and verify they reinstall.

Q: Which capability helps with parallel Android forwarding? appium:systemPort assigns a unique host port to each UiAutomator2 session. Device UDIDs must also be unique.

Q: Which evidence distinguishes an iOS WDA launch failure from a timeout? Xcode output and a WDA /status probe. A signing or build error requires provisioning work; a live service with slow responses may warrant a measured timeout adjustment.

Common Mistakes

  • Increasing every timeout after an immediate reset. A crashed process or unavailable port will still fail.
  • Treating curl /status as proof that the device helper works. Exercise a real session command too.
  • Reinstalling the Appium npm package before reading logcat or Xcode output. That can erase useful context without fixing a device-side failure.
  • Running adb on a laptop while the actual test runs in a container. Probe from the runner that owns the failing connection.
  • Sharing systemPort or wdaLocalPort among parallel workers. Make the allocation explicit and check the corresponding listener.
  • Leaving skipServerInstallation enabled while diagnosing an Android helper mismatch. That setting bypasses the reinstall check you need.
  • Copying /wd/hub from an old example into a root-path server configuration. Compare the actual client URL with the active server base path.

Conclusion

To fix Appium socket hang up reliably, identify the disconnected boundary, prove it with one small command, and repair the process, device transport, or port at that boundary. Then run a session command and the original failing action on the same runner and device. Keep the logs and port assignment with the test result so the next reset has a clear starting point.

Interview Questions and Answers

How would you triage an Appium socket hang up in production CI?

I would correlate the client failure timestamp with the Appium debug log and identify whether the request reached the server. If it did, I would find the last proxied request, then inspect ADB and logcat for Android or Xcode and WDA status for iOS. I would reproduce one command on the same runner and device before changing timeouts.

What does a successful Appium status response prove?

It proves the Appium listener can answer an HTTP request from that caller. It says nothing conclusive about a selected Android or iOS device because their automation helpers start or receive traffic later. I would follow it with a session and a proxied command.

How do you detect a UiAutomator2 crash?

I compare the reset with Android logcat entries for instrumentation and fatal exceptions. I also verify ADB can still run a shell command and inspect the helper packages on the device. A live ADB transport plus a fresh instrumentation fatal points toward the helper rather than the client connection.

Why is systemPort important in parallel Appium execution?

UiAutomator2 uses a host port forwarded to its device-side server. Two sessions competing for the same host port can misroute requests or fail to establish forwarding. I assign a unique systemPort and device UDID per worker, then inspect the active forwarding rules.

How would you diagnose WebDriverAgent socket resets?

I enable showXcodeLog, check the first build or launch error, and query WDA /status through its Mac-side port. Signing failure, a dead WDA process, and a port collision have different fixes. I would not assume that increasing wdaConnectionTimeout solves a failed build.

What distinguishes a client-to-server network failure from a device-side reset?

When the client cannot reach Appium, the server log has no matching request and a status probe from the runner fails. With a device-side reset, Appium logs the incoming request and often a proxy attempt before the connection closes. The two observations point to different network boundaries.

When is a timeout increase justified?

Only after I measure a slow operation, confirm the downstream service remains alive, and identify the specific timeout that ends the exchange. I change that limit narrowly and repeat the same operation. An immediate reset or a fatal process log is evidence against a timeout-only fix.

Frequently Asked Questions

What causes Appium socket hang up on Android?

The common causes are lost ADB transport, a UiAutomator2 instrumentation crash, a stale device-side helper, or a forwarding port collision. Compare Appium's last proxied request with adb state and logcat at the same timestamp before changing configuration.

How do I fix socket hang up in Appium on iOS?

Check whether WebDriverAgent built, launched, and answers its /status endpoint on the Mac-side port. Xcode signing or trust failures need device provisioning work; a port conflict needs a unique wdaLocalPort.

Does increasing newCommandTimeout fix socket hang up?

Usually no. newCommandTimeout controls how long Appium waits between commands, while a socket reset means an active HTTP connection closed. Measure the failing operation and inspect the downstream process before changing a read timeout.

Why does Appium /status work when my test fails?

The status route proves that the Appium HTTP server is responding. It does not start or validate UiAutomator2 or WebDriverAgent. Create a session and execute a device command to verify the full path.

Can parallel Appium tests cause socket hang up?

Yes, if workers share a device or host-side forwarding port. Give each Android worker a distinct systemPort and each real-device iOS worker a distinct wdaLocalPort, then verify the corresponding listeners during concurrent sessions.

Should I reinstall Appium after seeing socket hang up?

Only if evidence points to the host installation or extension. First inspect the server log, device transport, driver list, and platform logs. Reinstalling the npm package does not repair an offline device or WDA signing failure.

Why does this error occur only in Docker or CI?

The runner may resolve localhost to its own container, lack a route to the Appium service, or lack the Android device bridge. Run curl against /status and adb devices inside the exact runner environment to identify the missing connection.

Related Guides