Resource library

QA How-To

How to Fix Appium "Could not find a connected Android device"

Fix Appium could not find a connected Android device by checking ADB state, USB authorization, emulator boot, SDK paths, UDID, Docker, and CI visibility.

17 min read | 3,251 words

TL;DR

Run adb devices -l beside the Appium process. Get the target serial to device state, verify adb shell and boot completion, then set appium:udid to that serial; repair USB, emulator, SDK, wireless, or container visibility according to the observed ADB output.

Key Takeaways

  • Run adb devices -l in the environment that launches Appium and require a device row.
  • Approve the phone's USB debugging prompt when ADB reports unauthorized.
  • Wait for sys.boot_completed to return 1 before starting an emulator session.
  • Align ANDROID_HOME, Platform-Tools, and the ADB server across terminals and processes.
  • Use appium:udid with the exact live ADB serial, especially for parallel tests.
  • Check ADB from inside Docker or CI before debugging test capabilities.

To fix Appium Could Not Find a Connected Android Device, start where the error appears: during Android session creation or after a running session loses its ADB connection. Appium can only select a device that the ADB server visible to the Appium process reports as online. Run adb devices -l in that environment before changing your test code.

Could not find a connected Android device

The message may be wrapped in a WebDriver unknown error response or followed by an elapsed time. That wrapper does not identify the root cause. The device list, serial, SDK path, and process boundary do.

TL;DR

Run this in the same shell, container, or CI job that launches Appium:

adb devices -l
adb kill-server
adb start-server
adb devices -l

You need a row ending in device, such as emulator-5554 device. An empty list means connect a phone or start an emulator. unauthorized means accept the phone's USB debugging prompt. offline means repair the transport or wait for the emulator. If your shell sees an online row but Appium does not, compare the SDK and ADB server used by each process, then set appium:udid to that row's serial. Do not treat appium:deviceName as a serial selector. The Appium Android setup guide covers the broader toolchain.

What the Error Actually Means

The UiAutomator2 driver asks Android Debug Bridge (ADB) for connected Android transports while it starts a WebDriver session. If no usable transport survives selection, Appium cannot install or contact its on-device automation server. This is earlier than element lookup, app permissions, or a test assertion. A successful appium process and an open port 4723 prove only that the server started.

adb devices -l separates three states that often get called "connected": a physical USB cable is plugged in; ADB has discovered a serial; ADB has authorized the serial and marks it device. Only the last state is a reliable session target. Appium's UiAutomator2 setup documentation explicitly uses adb devices to establish this prerequisite.

Read the Appium server log around Getting connected devices or the device selection step. An empty list points below Appium to USB, emulator, network, SDK, or process isolation. A list containing a different serial points to capabilities. If the log names a different adb executable from the one you ran, your terminal check tested the wrong SDK. Keep the complete log; the client exception often strips away that distinction.

Root-Cause Decision Table

Symptom in the Appium environment Likely root cause First fix
adb devices -l has no rows after the header and a phone is plugged in USB data path, debugging, host permission, or device driver Enable USB debugging; change cable/port; inspect host detection
Serial shows unauthorized Phone has not trusted this host's ADB key Unlock phone and accept the RSA prompt
Serial shows offline or disappears repeatedly Stale ADB transport, reboot, unstable USB, or Wi-Fi loss Restart ADB, reconnect, then inspect transport
emulator -list-avds has names but ADB has no emulator row AVD exists but is not running Launch an AVD and wait for boot completion
Terminal sees device, Appium log sees zero devices Different SDK, ADB server, user, or environment Align ANDROID_HOME, PATH, and process context
Several online rows or an old udid Ambiguous or wrong device selection Set appium:udid to the exact current serial
Phone is paired over Wi-Fi but is absent from the list Pairing and active connection are separate states Use the current pairing and connect endpoints
Host sees device, container or CI process does not ADB runs across an isolation boundary Make ADB reachable from the Appium process

Follow the row that matches the output you actually have. Changing platformVersion or reinstalling Appium cannot repair a missing USB transport. Conversely, buying a cable will not fix a stale serial in your capabilities. The desired capabilities reference is useful after ADB itself is healthy.

1. Fix Appium Could Not Find a Connected Android Device When USB Detection Is Empty

First check whether the operating system sees the handset at all. On the phone, unlock the screen, enable Developer options and USB debugging, and choose a USB mode that allows data. Try a known data-capable cable directly in another port rather than assuming a charging cable supports data. A hub adds another failure point. Android Studio's hardware device instructions cover the on-device controls and host setup.

adb devices -l
# macOS: check whether the USB subsystem sees the phone
system_profiler SPUSBDataType
# Linux: check USB enumeration
lsusb
# Windows PowerShell: list the ADB executable and ADB transports
where.exe adb
adb devices -l

Use only the host-specific inspection line for your operating system. If the phone is absent from both the OS USB listing and ADB, change the physical path first. If the OS sees it but ADB does not, check USB debugging on the phone; on Windows, inspect Device Manager for a missing or incorrect OEM USB driver; on Linux, inspect USB permissions or udev rules for your distribution. Do not weaken permissions with a blanket chmod on USB devices.

After changing the cable, driver, or phone setting, disconnect and reconnect once. Verify with adb devices -l; the expected result is a stable serial marked device. Run the command twice a few seconds apart. A row that appears only briefly belongs in the offline/disconnect investigation below. For a phone, also run adb -s <serial-from-adb> shell getprop ro.product.model. A model name proves the ADB shell works, which is stronger than mere enumeration.

2. Authorize the Computer When ADB Reports unauthorized

A serial followed by unauthorized is already visible to ADB, but Android has not accepted this computer's debugging key. Look at the unlocked phone for the "Allow USB debugging?" prompt. Compare its RSA fingerprint with the computer you intended to trust, then approve it. The screen may hide the prompt behind the lock screen or another dialog. Reconnect the cable after approval if the state does not change.

adb devices -l
adb kill-server
adb start-server
adb devices -l
adb -s <serial-from-adb> shell getprop ro.build.version.release

Replace the placeholder with the first column from adb devices -l. The final command must return an Android release value. If adb still reports device unauthorized, use Developer options on the phone to revoke USB debugging authorizations, reconnect, and accept the new prompt. That resets trust for other computers too, so do it deliberately on a shared test phone. A server restart alone does not grant trust; approval happens on the device.

On a managed or locked-down phone, organizational policy may disable debugging or hide Developer options. In that case obtain a device provisioned for testing. Appium cannot bypass Android's authorization gate. The verification command is adb devices -l: it must say device, followed by a successful adb -s ... shell command. If the row flips to offline, continue with the next section instead of repeatedly tapping the authorization prompt.

3. Recover an offline or Intermittent ADB Transport

offline means ADB knows a serial but cannot communicate with it normally. That can happen during boot, after a cable disconnect, when a wireless network changes, or when two copies of ADB contend for a server. Preserve the original adb devices -l output before restarting anything, because the state is evidence.

adb devices -l
adb kill-server
adb start-server
adb devices -l
adb -s <serial-from-adb> shell getprop sys.boot_completed

A booted device returns 1 from sys.boot_completed. If the command cannot reach the serial, unplug and reconnect USB, change the cable or port, and watch for a stable device row. For an emulator, leave it running until Android finishes booting; an ADB row may precede a usable system. Avoid scripting a blind fixed sleep as the only readiness check. If multiple Android Studio, Appium, or CI jobs restart ADB concurrently, isolate jobs or serialize server restarts. Killing a shared ADB server can interrupt another test.

Check the selected transport directly with adb -s <serial-from-adb> shell echo ready; expect ready. If it drops between this check and session creation, collect USB and emulator logs instead of increasing Appium timeouts. appium:adbExecTimeout controls how long an individual ADB command may run; it does not make an absent device appear. The Appium wait strategies guide addresses application timing only after a device session exists.

4. Start and Finish Booting the Emulator

An Android Virtual Device (AVD) definition is a disk image and configuration, not a running device. Android Studio can show an AVD in Device Manager while adb devices remains empty. Start it in Android Studio or use the command-line emulator from the same SDK. The Android emulator command reference documents -list-avds and -avd.

"$ANDROID_HOME/emulator/emulator" -list-avds
"$ANDROID_HOME/emulator/emulator" -avd <avd-name>

Run the launch line in a separate terminal because the emulator remains attached to that process. Replace <avd-name> with one of the exact names listed. If the list is empty, create an AVD and install its system image through Android Studio's Device Manager first. Do not invent an AVD name in appium:avd and expect Appium to create its image.

In the Appium terminal, verify the transport and boot state:

adb devices -l
adb -s <emulator-serial> shell getprop sys.boot_completed
adb -s <emulator-serial> shell getprop ro.product.model

Expect device, then 1, then a model string. Use the actual serial from ADB, commonly an emulator- value. If another emulator is already running, do not assume the first serial matches the AVD you just launched. You can inspect adb -s <serial> emu avd name for an emulator transport and bind the desired serial with appium:udid. In headless CI, keep the emulator process alive for the entire test job and wait for sys.boot_completed before starting Appium. See mobile device farm testing when local emulator scheduling no longer fits your CI capacity.

5. Fix Appium Could Not Find a Connected Android Device When It Uses Another SDK

Your terminal and Appium may run under different users, startup scripts, IDE configurations, or containers. One can execute /path/A/platform-tools/adb while the other executes /path/B/platform-tools/adb. They may also contact different ADB server addresses or ports. Compare the exact executable and SDK environment in the process that starts Appium, not in an unrelated shell tab.

command -v adb
adb version
printf 'ANDROID_HOME=%s\nANDROID_SDK_ROOT=%s\n' "$ANDROID_HOME" "$ANDROID_SDK_ROOT"
"$ANDROID_HOME/platform-tools/adb" devices -l
appium driver doctor uiautomator2

On Windows PowerShell, use where.exe adb, adb version, $env:ANDROID_HOME, and & "$env:ANDROID_HOME\platform-tools\adb.exe" devices -l. The direct SDK-path command should list the same online serial as your ordinary adb devices -l. If not, fix ANDROID_HOME and PATH in the environment that launches Appium, then restart Appium. Prefer one installed SDK path over multiple Platform-Tools copies. An ANDROID_HOME directory points to the SDK root containing platform-tools, not to platform-tools itself.

The UiAutomator2 doctor checks prerequisites; it is valuable when the ADB binary is missing, yet a clean doctor report does not prove that a particular phone is online. If appium driver list --installed does not show uiautomator2, install it with appium driver install uiautomator2, then rerun the doctor. A missing driver usually produces a driver-selection error rather than this exact device error, so keep the diagnoses separate. The driver installation walkthrough explains extension management. Verify the repair by starting Appium from the corrected shell and checking that its log's ADB path and adb devices -l agree.

6. Select the Exact Online Serial With appium:udid

With several phones or emulators, Appium can autodetect a device you did not mean to use. A saved udid can also outlive a wireless reconnect, new emulator instance, or device replacement. UiAutomator2's capability reference says appium:deviceName does not select the target; appium:udid does. The serial must match the first column of the ADB list visible to the Appium server.

adb devices -l
adb -s <serial-from-adb> shell getprop ro.build.version.release

Copy the selected serial exactly, including an emulator prefix or Wi-Fi port. Then send a minimal W3C session request to an Appium server running at http://127.0.0.1:4723:

curl -sS -X POST http://127.0.0.1:4723/session \
  -H 'Content-Type: application/json' \
  -d '{"capabilities":{"alwaysMatch":{"platformName":"Android","appium:automationName":"UiAutomator2","appium:udid":"<serial-from-adb>"}}}'

Replace the placeholder before running it. A successful response contains value.sessionId; an error response contains value.error and value.message. A no-app UiAutomator2 session starts without launching your test app, so this isolates device selection from APK installation and app launch. Delete the created session through DELETE /session/<sessionId> when finished. If a row is online but Appium still rejects this exact serial, compare server logs for the ADB executable and inspect the platformVersion capability. Remove a stale platformVersion during diagnosis; if you need it later, obtain the value with the getprop command above. Parallel workers each need their own udid and distinct UiAutomator2 systemPort; see Appium parallel testing.

7. Reconnect a Phone Used Through Wireless Debugging

Pairing an Android device over Wi-Fi does not guarantee an active ADB connection today. Networks, IP addresses, and connect ports can change. On Android 11 or later, open Developer options, Wireless debugging. Keep the phone and computer on a reachable network. Read the current pairing address and code from "Pair device with pairing code"; the address for pairing is not necessarily the one shown on the main Wireless debugging screen for connecting.

adb pair <phone-ip>:<pairing-port>
# Enter the code shown on the phone when prompted.
adb connect <phone-ip>:<connect-port>
adb devices -l
adb -s <phone-ip>:<connect-port> shell getprop ro.product.model

Replace both endpoint placeholders with the phone's current values. The model command must return a string and the devices row must end in device. If adb connect cannot reach the phone, confirm both endpoints and check that VPN or client isolation on the Wi-Fi network is not blocking peer traffic. Re-pair only if the trust relationship is actually gone. Android's wireless debugging instructions describe the pairing flow and network requirements.

For reliable CI, a network phone needs a stable provisioning plan or a managed device farm. Do not persist a transient IP and port in a test suite's udid; derive the serial from the ADB list after connection, then pass it into that job's capabilities. A Wi-Fi row disappearing after a test starts is a transport failure, not an element wait problem. Verify with adb -s <serial> shell echo ready before each new session.

8. Make ADB Visible to Appium in Docker and CI

adb devices -l on the host tells you nothing about a separate container until you check inside it. A container has its own network namespace, environment, and filesystem; a cloud CI runner may have no USB device or hardware acceleration at all. Start with the exact process environment. If Appium is already in a container with Platform-Tools installed, inspect it directly:

docker exec <appium-container> sh -lc 'command -v adb; printf "ANDROID_HOME=%s\n" "$ANDROID_HOME"; adb devices -l'

Expect the same online serial the Appium process can use. If the host sees the phone but this command returns an empty list, choose an explicit transport architecture: run Appium on the host; expose a controlled host ADB server to the container and configure UiAutomator2's appium:remoteAdbHost plus appium:adbPort; or pass USB access and its required host permissions into the container. Merely mounting an APK or opening Appium port 4723 does not attach a phone. ADB server access must be restricted to trusted test infrastructure because it controls attached devices. Verify any remote ADB design from inside the container using the matching adb -H <adb-host> -P 5037 devices -l, then start Appium with the matching capabilities.

For a CI emulator job, fail early when no online device exists. Run this shell gate after launching the emulator and before Appium tests:

adb wait-for-device
serial=$(adb devices | awk '$2 == "device" { print $1; exit }')
test -n "$serial" || { echo 'No online Android device'; exit 1; }
test "$(adb -s "$serial" shell getprop sys.boot_completed | tr -d '\r')" = 1 || {
  echo "Android has not finished booting: $serial"; exit 1;
}
printf 'Ready Android serial: %s\n' "$serial"

adb wait-for-device waits for a transport, while sys.boot_completed distinguishes boot readiness. Set a CI job timeout so a missing emulator cannot wait forever. If your CI service has no emulator support, provision a supported self-hosted runner or device service; a test library cannot manufacture a physical transport. The Docker for QA guide covers container boundaries more generally. The gate's printed serial is the value to pass to appium:udid for that job.

How to Verify the Fix

Use three checks in order. First, in Appium's environment, adb devices -l shows the intended serial as device. Second, adb -s <serial> shell getprop sys.boot_completed returns 1 and adb -s <serial> shell echo ready returns ready. Third, create a minimal UiAutomator2 session with that serial using the curl request above. A successful session ID proves Appium selected a device and spoke to its automation driver; it does not yet prove your app's package or activity is correct.

After the minimal session works, restore your normal test capabilities one at a time: appium:app or appium:appPackage and appium:appActivity, then any platform filters. If the error changes to an app installation, activity launch, or Chromedriver error, the device-discovery problem is solved. Investigate the new message rather than returning to cable diagnostics. Keep the Appium log and the adb devices -l output from the same moment, particularly for intermittent failures.

A practical final smoke check is to start a session, read its sessionId, delete it, and start one more. This detects transports that work once and then drop. For a shared test lab, verify the chosen serial belongs to the assigned worker before running destructive app resets. Store the serial and the Appium server address in the run log, not a screenshot of a machine-specific Device Manager window.

Prevent It From Coming Back

Make device readiness an explicit prerequisite in local scripts and CI. Start the emulator or connect the phone, wait for ADB, check boot completion, then start tests. Capture adb devices -l, command -v adb, adb version, ANDROID_HOME, and the selected serial alongside Appium logs on failure. Those five facts usually show whether the break occurred before or inside Appium. Avoid letting concurrent jobs restart the same ADB server during active sessions.

Assign one serial per worker and generate capabilities from the live ADB list. For parallel UiAutomator2 sessions, also give each worker a distinct appium:systemPort; a port collision is a separate issue that can look like flaky device access later. Keep Platform-Tools and Appium extensions managed in one documented environment. When upgrading them, compare the toolchain as a unit and run appium driver doctor uiautomator2 before the full suite. The Appium mobile automation guide provides the broader workflow once discovery is stable.

For USB labs, label data-capable cables and devices, and use powered hubs only when needed. For Wi-Fi devices, reconnect and verify a shell command before reserving a worker. For containers, put the ADB topology in deployment configuration instead of assuming host USB is inherited. These practices turn a generic "device not found" exception into a short, observable setup failure.

Interview Questions and Answers

The eight model answers in interviewQnA cover ADB states, SDK mismatches, emulator readiness, exact serial selection, Docker boundaries, wireless reconnection, and how to isolate discovery from app launch. In an interview, lead with the observable adb devices -l result, then explain the specific next command. Practice explaining the diagnosis aloud at /practice.

Common Mistakes

  • Setting appium:deviceName to a visible phone model and assuming Appium will target that serial. Copy the ADB serial into appium:udid.
  • Treating unauthorized as an Appium bug. Android requires approval on the phone, even when the USB cable is fine.
  • Checking ADB on the host while Appium runs in Docker or a remote CI agent. Run the diagnostic where Appium runs.
  • Using a hard-coded sleep after emulator launch. Wait for an online transport and sys.boot_completed instead.
  • Restarting ADB repeatedly in a shared lab. A server restart can break other workers, so capture state and coordinate it.
  • Adding platformVersion, appium:app, and app launch settings before proving a minimal no-app session. Isolate discovery first.
  • Copying an old wireless endpoint into appium:udid. Reconnect, read the current serial, and verify adb shell.

Conclusion

Fix Appium "Could not find a connected Android device" by proving that Appium's own ADB environment sees one online, booted serial, then targeting that serial with appium:udid. Use the decision table to repair USB authorization, emulator startup, SDK mismatch, wireless transport, or container isolation according to the observed state. Once a minimal session succeeds, restore app-specific capabilities and run your normal test.

Interview Questions and Answers

What is the first diagnostic for the Appium connected Android device error?

I run adb devices -l in the same environment that starts Appium. An online row proves transport discovery, while an empty, unauthorized, or offline list identifies the next layer to investigate. I also keep the Appium server log because the client exception may omit the ADB path.

How can adb devices work in a terminal while Appium sees no devices?

The two processes may use different SDK installations, ADB server endpoints, users, or containers. I compare command -v adb, ANDROID_HOME, and device lists from both process contexts. Then I restart Appium from the corrected environment and inspect its log for the ADB executable.

What does an unauthorized ADB device indicate?

ADB has discovered the phone but Android has not trusted this host key. I unlock the phone, approve the RSA prompt, and confirm adb shell works. If the prompt does not appear, I reconnect and may revoke debugging authorizations on that test phone before retrying.

How do you prove an emulator is ready for Appium?

I distinguish an AVD definition from a running emulator. After launching it, I require adb devices -l to show a device row and adb shell getprop sys.boot_completed to return 1. A fixed sleep is insufficient because boot duration varies by runner.

How do appium:deviceName and appium:udid differ?

UiAutomator2 does not use deviceName as an exact device selector. udid identifies the transport by the serial shown in the Appium-visible ADB list. In parallel runs I assign one udid and one distinct systemPort per worker.

What is your approach when Appium in Docker cannot see a host-connected phone?

I check adb devices -l inside the container to prove the boundary. Then I choose an explicit topology, such as running Appium on the host or connecting the driver to a restricted host ADB server with remoteAdbHost and adbPort. I verify an ADB shell from that topology before opening a session.

Why might a paired Wi-Fi device disappear from Appium?

Pairing records trust, while the active ADB connection depends on the current network endpoint. I inspect Wireless debugging on the phone, reconnect to the current address and port, and use the resulting serial as udid. A successful adb shell command confirms the connection is usable.

How do you isolate device discovery from app launch failures?

I request a minimal UiAutomator2 session with platformName, automationName, and the live udid, without an APK or package. If it returns a session ID, discovery works. I add app and activity settings afterward and classify any new error separately.

Frequently Asked Questions

Why does Appium say it could not find a connected Android device?

The UiAutomator2 driver cannot select an online Android transport from the ADB environment used by Appium. Check adb devices -l from that environment; empty, unauthorized, and offline lists require different fixes.

Why is my phone listed as unauthorized in adb devices?

The device has not approved the computer's debugging key. Unlock the phone, accept the USB debugging prompt, and verify that adb devices -l changes to device before starting Appium.

Why does Android Studio show an emulator but Appium cannot find it?

Android Studio may show an AVD definition that has not been launched. Start the emulator, wait for adb devices -l to show its serial as device, and confirm sys.boot_completed returns 1.

Does appium:deviceName select a specific Android phone?

No. UiAutomator2 uses appium:udid to target an exact ADB serial. Read the serial from the same ADB server Appium uses, especially when multiple devices are attached.

How do I fix Appium device discovery in Docker?

Run adb devices -l inside the container first. If only the host sees the device, provide the container with a controlled path to the host ADB server or run Appium where the device is visible, then verify the serial inside Appium's environment.

Can appium:adbExecTimeout fix a missing device?

It can extend the wait for an individual ADB command, but it cannot authorize or attach a device. Establish a stable device row and a working adb shell command before tuning timeouts.

What should a CI job check before opening an Appium session?

Check that adb reports a serial in device state and that adb shell getprop sys.boot_completed returns 1. Print the serial in the job log and pass it into appium:udid for that run.

Related Guides