QA How-To
How to Fix Appium "The instrumentation process is not running"
Fix Appium instrumentation process is not running by checking ADB, Android logcat, UiAutomator2 server APKs, session teardown, emulator readiness, and CI.
18 min read | 3,437 words
TL;DR
Check the failing device's ADB state, Appium server log, and logcat at the first instrumentation exit. Repair the specific transport, package, Android crash, teardown, readiness, or worker conflict, then create a new UiAutomator2 session and request page source.
Key Takeaways
- Find the first instrumentation exit in Appium logs and correlate it with Android logcat.
- Confirm the selected ADB serial remains online and booted from Appium's own environment.
- Check both UiAutomator2 helper packages and the registered instrumentation runner before reinstalling.
- Treat commands sent after DELETE /session as client lifecycle errors, not Android crashes.
- Use one device and systemPort per parallel worker; verify inside Docker or CI.
- Prove recovery with a fresh native session and a page-source request.
To fix Appium instrumentation process is not running, diagnose the Android UiAutomator2 session when a command such as page source, element lookup, or screenshot fails after the on-device instrumentation exits. The client message identifies the stopped server, but the Appium server log and Android logcat explain why it stopped.
Original error: 'POST /element' cannot be proxied to UiAutomator2 server because the instrumentation process is not running (probably crashed). Check the server log and/or the logcat output for more details
The request path may be GET /source or another proxied command. Capture the first failure, not just later retries: the instrumentation may have exited seconds before the command that exposed it. This guide moves from the device transport through the Android process, installed server packages, client session lifecycle, and parallel workers.
TL;DR
Keep the failing Appium server log. In the same machine or container as Appium, select the actual device and check that ADB can still run a shell command:
adb devices -l
serial=$(adb devices | awk '$2 == "device" {print $1; exit}')
test -n "$serial" || { echo 'No online Android device'; exit 1; }
adb -s "$serial" shell getprop sys.boot_completed
adb -s "$serial" shell pm list instrumentation
adb -s "$serial" logcat -d -b crash -v time
Use the serial from your failing run if several devices are attached; the automatic selection above is only a single-device example. A missing or offline ADB row is a transport problem. A crash buffer with a Java or native exception points to a process failure. Missing or mismatched Appium server packages call for a targeted reinstall. A clean exit immediately after client teardown calls for session-lifecycle work. Restarting the test without identifying which of these occurred often hides the evidence.
What the Error Actually Means
The UiAutomator2 driver runs an instrumentation test package on Android. That instrumentation starts an HTTP server on the device, and Appium forwards many native WebDriver commands to it. Once the instrumentation has exited, Appium cannot proxy another native command through the old session. The UiAutomator2 driver documentation describes the on-device server and its session-start behavior; the server repository shows the AndroidJUnitRunner instrumentation entry point.
The exception does not prove that your app under test crashed. The Appium server process can remain healthy while its device-side server dies. Conversely, the Android app can crash while instrumentation stays alive, allowing Appium to return a different app-state error. Locate the earliest Instrumentation exit line, FATAL EXCEPTION, ADB disconnect, or explicit DELETE /session near the failing timestamp. Preserve the original logcat before resetting ADB, uninstalling packages, or rebooting.
Distinguish startup from mid-session failure. A startup failure occurs before POST /session returns a usable session ID and often involves installation, runner registration, boot readiness, or launch timing. A mid-session failure occurs after one or more commands worked; transport loss, Android process termination, session teardown, and parallel interference become more likely. The Appium Android setup guide covers the prerequisite toolchain, while this guide focuses on the already selected UiAutomator2 instrumentation.
Root-Cause Decision Table
| Symptom | Root cause to investigate | Fix and proof |
|---|---|---|
adb devices -l shows offline, unauthorized, or no target serial |
ADB transport disappeared or changed | Restore an online serial and run a device shell command |
pm list instrumentation lacks the Appium test runner, or startup reports Unable to find instrumentation target package |
Cached server/test APKs are missing or incompatible | Reinstall the driver-managed packages, then create a fresh session |
logcat -b crash contains a stack trace for an Appium package |
Android killed or crashed the device-side server | Read the first exception and repair its specific cause |
Server log shows DELETE /session, then another command uses the same ID |
Test teardown or command race | Serialize teardown and create a new session |
Emulator is visible, but sys.boot_completed is empty or memory pressure appears in logs |
Device is not ready or is resource constrained | Wait for boot; restore emulator capacity; retry a minimal session |
| Driver log shows a launch timeout while instrumentation starts slowly | Insufficient launch allowance after other checks pass | Raise the documented launch timeout modestly and verify the server stays alive |
| Failures happen only with concurrent workers | Shared device or systemPort collision |
Assign one device and host port per worker |
| Host ADB works, but Docker or CI cannot see the device | Different process and ADB environment | Test ADB where Appium runs and make its transport explicit |
Use this table as a branch selector. Each numbered section includes a command that checks the repair. If your logcat shows a concrete exception, follow that exception instead of applying every change in the table.
1. Fix Appium Instrumentation Process Is Not Running After ADB Disconnects
Start with the exact serial from the failed session's appium:udid or Appium log. The transport can vanish when a USB cable drops, wireless debugging changes endpoint, an emulator restarts, or another job restarts the shared ADB server. A device shown as offline is discovered but cannot carry a reliable shell command. unauthorized requires approval on the phone, not a longer Appium timeout.
adb devices -l
serial='<serial-from-the-failing-session>'
adb -s "$serial" get-state
adb -s "$serial" shell echo ready
adb -s "$serial" shell getprop sys.boot_completed
Replace the placeholder with the first column of the relevant adb devices -l row. The expected state is device, the shell prints ready, and a fully booted system returns 1. If USB is unstable, use a data-capable cable and a direct port, approve the debugging prompt, and run the same four checks twice several seconds apart. For an emulator, wait until its Android system has finished booting. For wireless debugging, reconnect to the current device address before copying its current serial into the test.
A working shell after a disconnect does not revive an old Appium session. End the failed client session and start a new one after the transport is stable. Do not blindly run adb kill-server on a shared lab host; it disconnects every worker using that ADB server. If the row remains device but the session dies, move to Android logs. The Appium Android setup guide covers USB authorization, SDK paths, and emulator detection in depth.
2. Fix Appium Instrumentation Process Is Not Running With Stale Server APKs
The driver installs both io.appium.uiautomator2.server and its .test instrumentation package. An old package left on a device after a driver change, a skipped installation, or an incomplete install can stop the runner before it serves requests. The driver's appium:skipServerInstallation option deliberately bypasses installation and checks; remove it or set it to false while diagnosing. This is distinct from reinstalling the app under test.
serial='<serial-from-the-failing-session>'
adb -s "$serial" shell pm path io.appium.uiautomator2.server
adb -s "$serial" shell pm path io.appium.uiautomator2.server.test
adb -s "$serial" shell pm list instrumentation
appium driver list --installed
The package commands should return APK paths, and the instrumentation list should include the Appium test runner. If either package is missing, stop the Appium server before cleanup. For one dedicated test device, uninstall the two Appium helper packages and let a normal new UiAutomator2 session install the matching pair:
adb -s "$serial" uninstall io.appium.uiautomator2.server.test
adb -s "$serial" uninstall io.appium.uiautomator2.server
adb -s "$serial" shell pm list instrumentation
An uninstall may report that a package was not installed; that confirms it was already absent. The final listing should no longer show the old Appium runner. Then start Appium with the installed driver and create a fresh session without skipServerInstallation. Verify the two pm path commands and the runner listing again after session creation. On a machine dedicated to Appium devices, the documented appium driver run uiautomator2 reset also clears cached UiAutomator2 driver binaries from all connected devices, so avoid it on a shared host without coordinating the affected sessions. The Appium driver-management guide explains the extension CLI.
3. Find the Actual Android Crash Before Changing Capabilities
A crash buffer is more useful than the final WebDriver exception. Android may report FATAL EXCEPTION with a Java stack trace, a native tombstone, or a package-specific permission failure. Collect the logs immediately after one reproducible failure. A long-running farm should capture a timestamped logcat stream from before session creation, because the circular device buffer can overwrite an early crash.
serial='<serial-from-the-failing-session>'
adb -s "$serial" logcat -d -b crash -v time
adb -s "$serial" logcat -d -v time | grep -E 'FATAL EXCEPTION|AndroidRuntime|io.appium.uiautomator2|INSTRUMENTATION_STATUS|am_proc_died' | tail -n 100
adb -s "$serial" shell pm list instrumentation
Read the first exception and its Caused by chain. Match the process or package name to the crash. If the failing process belongs to the app under test, first reproduce the app launch outside Appium and investigate that app build. If the process is an Appium package, check whether its install is intact, whether Android denied a permission, whether a device management policy stopped it, and whether the OS was under pressure. Avoid presenting every crash as a "known Appium bug"; the stack trace and device policy decide the fix.
You can test runner registration outside Appium after stopping the Appium session. The following command starts the documented instrumentation directly and normally keeps running while its server waits for work. Use a separate terminal, inspect its immediate output, and stop it with Ctrl-C before starting Appium again:
adb -s "$serial" shell am instrument -w io.appium.uiautomator2.server.test/androidx.test.runner.AndroidJUnitRunner
An immediate INSTRUMENTATION_FAILED or exception gives a narrower failure than a client proxy message. If the runner stays active but Appium sessions still die, compare Appium's port forwarding and logs. This manual command is diagnostic, not a replacement for the driver-managed session. Verify the repair with a new minimal session and a successful page-source request, as shown below.
4. Stop Reusing a Session After Teardown or Timeout
A common mid-suite sequence is: the test framework deletes a session, a background helper issues GET /source or a screenshot request, and the client reports dead instrumentation. The driver documentation also notes that appium:newCommandTimeout can delete a session after the client stops sending commands. Search the server log for DELETE /session and the session ID of the failing request. If deletion came first, the command is using a dead handle even if Android exited cleanly.
# Inspect the saved Appium server log for one session ID.
grep -E 'DELETE /session|POST /session|newCommandTimeout|instrumentation process' appium.log
The example assumes you saved the server log as appium.log; replace that filename with your actual log. Put client teardown in one owner, after all test and evidence tasks have joined. For a manually managed W3C session, the teardown request is:
session_id='<session-id-to-close>'
curl -sS -X DELETE "http://127.0.0.1:4723/session/$session_id"
grep -F "DELETE /session/$session_id" appium.log
The grep line verifies that the server received the deletion for that exact ID; compare its timestamp to the last test command. Do not share a mutable driver object across tests that run concurrently. If a worker must keep an idle session open, set appium:newCommandTimeout in seconds to a value that matches its legitimate idle interval, but close it deliberately at the end. A higher timeout does not resurrect a session already deleted.
Verification is behavioral: create a new session, run the same command sequence, and confirm that no DELETE /session for that ID precedes the last intended command. Then delete the session once. A second command against the deleted ID should be treated as a test bug. The Appium wait strategies guide helps distinguish command timing inside a live session from this lifecycle failure.
5. Give the Emulator a Ready and Stable Android System
An emulator can appear in adb devices before Android finishes booting, and a constrained CI runner can later kill background processes under memory pressure. A device row is therefore necessary but not sufficient. Use the boot property and a real shell command before opening a session, then compare the crash timestamp with emulator and host resource logs if instrumentation stops during the suite.
serial='<emulator-serial-from-adb>'
adb -s "$serial" wait-for-device
while [ "$(adb -s "$serial" shell getprop sys.boot_completed | tr -d '\r')" != 1 ]; do
sleep 2
done
adb -s "$serial" shell echo ready
adb -s "$serial" logcat -d -v time | grep -E 'lowmemorykiller|lmkd|am_kill|io.appium.uiautomator2' | tail -n 80
Put an outer timeout on the CI job so a failed emulator boot cannot loop forever. The shell check must print ready. If lmkd or another process-death record names the Appium server or test package at the failure time, reduce the number of simultaneous emulators, provide the runner with sufficient resources, or move that workload to a capable runner. Do not assume an arbitrary fixed sleep proves readiness.
If the app under test deliberately changes Wi-Fi or mobile data during a test, inspect that action as well. The UiAutomator2 documentation warns that changing connectivity can terminate or disconnect its on-device REST server. Restore the connection and open a fresh session; choose appium:noReset only if you need to preserve app state and understand its effects. Verify by repeating one minimal session and its page-source request after the emulator has fully booted, then run the app-specific test.
6. Adjust Launch Timing Only When the Server Is Slow, Not Dead
The documented appium:uiautomator2ServerLaunchTimeout is measured in milliseconds and limits how long the driver waits for its on-device server to listen. Increase it only when ADB remains healthy, packages are installed, and logs show that instrumentation eventually starts rather than crashes. A timeout change is useful for a slow emulator cold start; it cannot repair INSTRUMENTATION_FAILED, a disconnected serial, or a fatal exception.
For a diagnostic session, add the real capability to the W3C payload:
serial='<serial-from-adb>'
response=$(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\",\"appium:uiautomator2ServerLaunchTimeout\":60000}}}")
session_id=$(printf '%s' "$response" | python3 -c 'import json,sys; print(json.load(sys.stdin)["value"]["sessionId"])')
curl -sS "http://127.0.0.1:4723/session/$session_id/source" | python3 -c 'import json,sys; assert json.load(sys.stdin)["value"]'
curl -sS -X DELETE "http://127.0.0.1:4723/session/$session_id"
The value is an example allowance, not a required setting. Replace the serial with the one Appium sees. Keep the normal appium:skipServerInstallation behavior so the device-side package is checked. If the error happens on an already running session, launch timeout is not the governing limit; inspect the crash or session deletion at that later time. The separate appium:uiautomator2ServerReadTimeout controls waiting for HTTP responses from a running server, and appium:adbExecTimeout controls ADB command waits. None should be used to conceal a vanished process.
Verify by recording when instrumentation starts and when the new session becomes ready. The next page-source request must succeed too. If the server launches within the extra allowance and remains alive across repeated sessions, keep the smallest allowance that fits that environment. If the log shows a process exit before the limit, revert the change and investigate the exit. The desired capabilities reference provides the broader capability model.
7. Isolate Devices and Ports in Parallel Runs
Parallel Appium workers must not command the same device unintentionally. Each Android worker needs a distinct appium:udid and its own host appium:systemPort for the UiAutomator2 server. The driver can select a free port automatically, but explicit assignments make concurrent jobs and logs easier to audit. Reusing a device or port can disrupt another worker's forwarding or session even when each individual test passes alone.
adb devices -l
# Run this on the Appium host for each proposed host port.
lsof -nP -iTCP:8201 -sTCP:LISTEN
lsof -nP -iTCP:8202 -sTCP:LISTEN
An empty lsof result means no process is listening at that instant. It does not reserve the port. Assign the ports in your worker configuration before starting jobs, for example worker A uses one online serial with systemPort 8201 and worker B uses a different online serial with systemPort 8202. Check both serials before launching the workers:
serial_a='<first-adb-serial>'
serial_b='<second-adb-serial>'
test "$serial_a" != "$serial_b"
adb -s "$serial_a" shell echo ready
adb -s "$serial_b" shell echo ready
Set appium:udid to the respective serial and appium:systemPort to 8201 or 8202 in each worker's W3C capabilities. The specific port numbers are examples within the driver's documented range; avoid collisions with existing local jobs. Use the exact serial returned by ADB, not a display name.
Verify that Appium logs associate each session with its intended serial and port. Start both workers, perform a page-source request on each, then close only one session. The other must still answer. If stopping A kills B, inspect shared teardown scripts, ADB restarts, and port mappings. The Appium parallel testing guide covers worker ownership beyond this failure.
8. Make Docker and CI Observe the Same Device as Appium
A host shell that sees an Android phone does not prove that Appium inside Docker can see it. Containers have separate filesystem, environment, and often network paths. Run the device checks inside the Appium container before debugging capabilities. The official driver setup expects a working Android SDK and ADB transport in the process environment that starts sessions.
docker exec <appium-container> sh -lc 'command -v adb; adb devices -l; adb shell getprop sys.boot_completed'
Replace the container placeholder. This command assumes exactly one online device; if several are attached, pass -s <serial> to the two device commands. An empty list inside the container requires a deliberate device or ADB-server topology, such as running Appium on the host, exposing a restricted host ADB server to the container, or granting the container access to the intended USB device. Opening port 4723 alone exposes Appium's HTTP endpoint, not an Android transport. If using a remote ADB server, check it from inside the container with adb -H <adb-host> -P 5037 devices -l, and configure the documented appium:remoteAdbHost and appium:adbPort for the same endpoint. Restrict that endpoint to trusted infrastructure because ADB controls the attached device.
In CI, gate tests on boot readiness and record evidence from the runner, not a developer laptop:
serial=$(adb devices | awk '$2 == "device" {print $1; exit}')
test -n "$serial" || { echo 'No online Android device in this CI job'; exit 1; }
boot=$(adb -s "$serial" shell getprop sys.boot_completed | tr -d '\r')
test "$boot" = 1 || { echo "Android not booted: $serial"; exit 1; }
adb -s "$serial" shell pm list instrumentation
printf 'Ready device: %s\n' "$serial"
The package list may be empty before Appium installs its helper APKs; that is evidence to compare after session creation, not an automatic failure. Print the serial and use it as appium:udid for the job. On failure, retain Appium server logs and logcat from the same container or runner. The Docker for QA guide explains these environment boundaries.
How to Verify the Fix
Verify the repair with a minimal native session before adding your app, WebView, or complex framework setup. Run the following from the Appium host with Python 3, ADB, and a running Appium server at http://127.0.0.1:4723. It picks one online device; set ANDROID_SERIAL yourself when several are present. The script uses standard W3C WebDriver endpoints and deletes the session in finally.
cat > smoke_uia2.py <<'PYCODE'
import json
import os
import subprocess
import urllib.error
import urllib.request
base = os.environ.get("APPIUM_URL", "http://127.0.0.1:4723").rstrip("/")
serial = os.environ.get("ANDROID_SERIAL")
if not serial:
rows = subprocess.check_output(["adb", "devices"], text=True).splitlines()
devices = [row.split()[0] for row in rows[1:] if len(row.split()) >= 2 and row.split()[1] == "device"]
if len(devices) != 1:
raise SystemExit(f"Expected one online device or ANDROID_SERIAL, found {devices}")
serial = devices[0]
payload = {"capabilities": {"alwaysMatch": {
"platformName": "Android",
"appium:automationName": "UiAutomator2",
"appium:udid": serial
}}}
session_id = None
try:
request = urllib.request.Request(
f"{base}/session",
data=json.dumps(payload).encode(),
headers={"Content-Type": "application/json"},
method="POST",
)
with urllib.request.urlopen(request, timeout=120) as response:
result = json.load(response)
session_id = result["value"]["sessionId"]
print(f"Session started: {session_id} on {serial}")
with urllib.request.urlopen(f"{base}/session/{session_id}/source", timeout=60) as response:
source = json.load(response)["value"]
assert isinstance(source, str) and source, "Empty page source"
print(f"Page source returned {len(source)} characters")
finally:
if session_id:
request = urllib.request.Request(f"{base}/session/{session_id}", method="DELETE")
with urllib.request.urlopen(request, timeout=30):
pass
print("Session deleted")
PYCODE
python3 smoke_uia2.py
A successful run prints a session ID, a nonzero page-source length, and a deletion line. If POST /session fails, look at installation, runner launch, and boot readiness. If session creation succeeds but GET /source fails, inspect the first instrumentation exit and logcat lines between those operations. If the smoke script passes but your suite fails, compare its extra capabilities, test teardown, app behavior, and parallel-worker assignment. The script does not prove that the application under test launches correctly; add appium:app or package/activity capabilities only after the native server survives this check.
For a reproducible incident, save three synchronized artifacts: Appium server log, adb devices -l output, and Android logcat near the first failure. Record the selected serial and whether the failure occurred at startup or after a successful command. These facts let another engineer distinguish a process crash from an ordinary stale-session request.
Prevent It From Coming Back
Make the device check a prerequisite in local scripts and CI. Require an online serial, sys.boot_completed equal to 1, and a working shell command before the test runner starts. Log command -v adb, adb version, the serial, installed UiAutomator2 driver listing, and the chosen Appium server address. These values expose mismatched SDKs and container boundaries without guessing.
Own every session in one worker. Create it during setup, stop background evidence collectors before teardown, delete it once, and discard the client object. Do not reuse the same physical device in two workers or let a cleanup job restart a shared ADB server. Assign explicit udid and systemPort values for parallel execution. If you intentionally upgrade the UiAutomator2 driver, run appium driver doctor uiautomator2 and a minimal session smoke check on a representative device before the full suite.
Keep a short failure artifact from the first occurrence, especially logcat's crash buffer and Appium's instrumentation-exit line. A retry may pass after a transient cable drop, but without the first trace the next recurrence is harder to diagnose. Treat an Android stack trace as its own incident and fix its cause; treat a clean DELETE /session as a client-lifecycle issue. The Appium mobile automation guide places this guard in a larger mobile test workflow.
Interview Questions and Answers
The model answers in interviewQnA cover the on-device architecture, startup versus mid-session failures, logcat evidence, stale APKs, session ownership, emulator readiness, port allocation, and container visibility. In a technical interview, start with the observation that distinguishes your hypothesis: the ADB state, first process-exit line, crash trace, or session deletion. Then name the command that would confirm it. Practice delivering that reasoning with a concrete device log at QA interview practice.
Common Mistakes
- Raising every timeout after seeing "probably crashed." A timeout cannot start a missing Android package or reverse a fatal exception; inspect the first exit.
- Reinstalling the application under test when the missing package is
io.appium.uiautomator2.server.test. Check the package named inpm list instrumentation. - Treating
adb deviceson the laptop as proof for Appium running in Docker or on a CI agent. Check inside the process boundary. - Keeping
appium:skipServerInstallationenabled during a driver change. It can preserve incompatible device-side helpers. - Running the driver-wide reset on a shared host without identifying every attached device. Use targeted uninstalls for one dedicated device.
- Starting a second session with the same device and host port, then blaming the app under test for the other worker's failure.
- Sending screenshot or source commands after teardown. The old session ID cannot gain a new instrumentation process.
- Using a fixed emulator sleep as the only readiness gate. Check boot completion and a working ADB shell.
- Discarding logcat on retry. A later pass does not explain why the first Android process stopped.
Conclusion
Fix Appium instrumentation process is not running by proving where the on-device server stopped: ADB transport, runner installation, Android crash, session lifecycle, emulator readiness, or worker isolation. Start with the first Appium exit line and nearby logcat, apply the matching repair, then run a minimal session that reads page source and closes cleanly. Once that passes, restore your app-specific capabilities and rerun the failing test.
Interview Questions and Answers
What does the UiAutomator2 instrumentation process do in an Appium Android session?
It hosts the on-device UiAutomator2 REST server used for many native WebDriver commands. Appium runs on the host and proxies those commands to the Android process. If the instrumentation exits, later commands cannot be delivered through that session.
What is your first diagnostic when this proxy error appears?
I preserve the first Appium server error and collect logcat for the same device and time. I also run adb devices -l and a shell command in Appium's environment. That separates transport loss from an Android process failure before I change capabilities.
How do you separate a startup failure from a mid-session failure?
I check whether POST /session returned a session ID and whether any native commands succeeded. Failure before the ID points to installation, runner registration, boot readiness, or launch timing. Failure after successful commands makes disconnects, process death, teardown, and parallel interference more likely.
What evidence proves stale or missing UiAutomator2 server APKs?
I inspect pm path for both io.appium.uiautomator2.server packages and pm list instrumentation for the AndroidJUnitRunner entry. A missing package or target-registration error supports an installation problem. On a dedicated device, I remove the helper packages and let a normal driver session reinstall them, then verify the runner appears.
Why is logcat more useful than the client exception?
The client exception reports only that Appium could no longer proxy a command. Logcat may contain the first Java exception, native crash, process kill, or instrumentation failure with the responsible package name. I line that up with the Appium instrumentation-exit timestamp.
When would you change uiautomator2ServerLaunchTimeout?
Only after proving the device stays online, Android is booted, helper packages are valid, and the instrumentation eventually listens. I would raise the millisecond allowance enough for that environment, run a minimal session, and check the next page-source command. I would not use it for a process that actually exits.
How can client teardown look like an instrumentation crash?
After DELETE /session or an idle session timeout, the device-side server can be stopped. A background screenshot or page-source task still holding the old session ID then fails. I make teardown wait for all tasks, delete once, and never reuse that client.
How do you design parallel Android Appium workers?
Each worker gets an exact ADB serial through appium:udid and a distinct host appium:systemPort. I avoid shared ADB restarts and ensure one worker's cleanup cannot delete another's session. I verify both sessions can answer page-source commands concurrently.
What changes when Appium runs in Docker?
I check adb devices and an Android shell command inside the container, because host visibility does not cross the boundary automatically. I then provide an explicit USB or restricted ADB-server path and align the driver's ADB host settings. I validate the serial from the same environment before creating a session.
Frequently Asked Questions
What does Appium's instrumentation process is not running error mean?
Appium tried to proxy a native command to its UiAutomator2 server on Android after the instrumentation hosting that server exited. The final proxy error does not identify why it exited; compare the Appium server log with Android logcat at the first failure.
Can my app under test cause the UiAutomator2 instrumentation to stop?
It can contribute through device state, resource pressure, or an interaction that disrupts the on-device server, but an app crash and an instrumentation crash are separate events. Match the process name and first exception in logcat before assigning the cause.
Which Android packages should I check for a missing Appium instrumentation runner?
Check io.appium.uiautomator2.server and io.appium.uiautomator2.server.test with adb shell pm path, then inspect adb shell pm list instrumentation. The test package should register the AndroidJUnitRunner used by the device-side server.
Should I increase uiautomator2ServerLaunchTimeout?
Only when a healthy, booted device eventually starts the server but exceeds the current launch allowance. The capability is measured in milliseconds and does not repair a crash, absent package, ADB disconnect, or command sent after session deletion.
How do I distinguish a real crash from a deleted Appium session?
Search the Appium log for DELETE /session and compare its session ID and timestamp with the failing command. A deletion before the command points to teardown or an idle timeout; a logcat exception before deletion points toward the Android process.
Can two parallel Appium tests trigger this error?
Yes, if they share a device, host systemPort, ADB restart, or teardown path. Assign each worker its own live udid and systemPort, then prove both sessions can answer commands while the other remains active.
Why does the error appear only in Docker or CI?
The Appium process may see a different ADB server, SDK, device list, or emulator boot state from the developer's shell. Run adb devices and the boot-property check inside the container or CI job and keep its logcat with the Appium log.
Related Guides
- How to Fix "Cypress could not verify that this server is running"
- How to Fix Playwright "Element is not attached to the DOM"
- How to Fix "Playwright Test did not expect test() to be called here"
- How to Fix "The Cypress binary is missing" in CI
- How to Fix Appium "Could not find a connected Android device"
- How to Fix Appium WebDriverAgent Failed to Start on iOS