Troubleshooting
My Android emulator does not show up#
- Run
adb devices. If the emulator is not listed there, EmuLabZip cannot see it either. Restart it, or runadb kill-server && adb start-server. - The device picker footer shows adb unavailable when
adbcannot be found. Install the Android SDK platform tools, or pointANDROID_HOMEorEMULABZIP_ADBat your SDK. - A device listed as unauthorized is waiting for you to accept the USB debugging prompt.
- A custom ADB server port must be set with
ANDROID_ADB_SERVER_PORTorADB_SERVER_SOCKETfor EmuLabZip too.
My simulator does not show up#
- Only booted iOS simulators are listed. Check with
xcrun simctl list devices booted. - The footer shows simctl unavailable when Xcode's command line tools are missing. Run
xcode-select --install, orsudo xcode-select -s /Applications/Xcode.appif several Xcode versions are installed.
The log is empty#
- On Android, check that
adb logcatprints lines. - Look at the minimum level and the filters; Reset filters appears when lines exist but none match.
- The app filter needs the app to be running. Start the app; the filter picks up the new process id automatically.
The log is too busy#
See The unified log is busy. On Android, raise the minimum level or filter by tag.
Screenshots fail#
- On Android,
adb exec-out screencap -p > shot.pngmust work. Some secure screens (DRM video, banking apps) are black by design. - On iOS,
xcrun simctl io booted screenshot shot.pngmust work.
Storage says "only debuggable apps can be browsed"#
Android only lets run-as read the private data of debuggable apps. Install a debug build of your app, or try the
tools with the sample app (tools/sample-app/install.sh). Shared storage works for every app.
Heap dumps fail on Android#
am dumpheap needs a debuggable app, or an emulator image of the userdebug/eng type (images without Google Play).
The error shows the reason Android gave, for example Process not debuggable.
Performance shows no frame rate#
Frames are only counted while the app draws. Interact with the app; a static screen renders nothing. On the iOS Simulator, frame metrics arrive with Instruments traces in Phase 4.
Network: nothing shows up#
- Check that the device says sending traffic here. On Android,
adb shell settings get global http_proxyshould print127.0.0.1:<port>. - Some apps ignore the system proxy (those that open sockets themselves, or use HTTP/3). They cannot be captured.
- Apps that cache heavily may not ask the network at all. Clear their data or use a fresh URL.
Network: HTTPS requests fail or show as "Connections"#
The device does not trust the certificate, or the app pins its server's. Press Certificate and follow what it says. On Android images from Google Play only Chrome and apps that allow user certificates will trust it; see the certificate. A banner names the hosts that are being passed through; use Decrypt again after fixing it.
Network: the device or the Mac is still pointing at the proxy#
Press Disconnect, or run adb shell settings put global http_proxy :0 for Android. For the Mac, open EmuLabZip
once: it restores the proxy settings it saved if an earlier run was killed. Otherwise turn the proxies off in
System Settings › Network › Details › Proxies.
Network: macOS asks for a password#
Changing the Mac's proxy is a system setting. EmuLabZip tries as you first and asks for administrator rights only if macOS refuses.
Network: a rule does nothing#
Rules see decrypted requests, so HTTPS needs the certificate installed, and a host that rejected it is passed through
and cannot be changed. The first enabled rule that matches wins; move the one you expect above the others. A host
pattern matches the host only (api.example.com, not https://api.example.com/).
Network: HTTP/3 shows no h3#
The feature is off by default (HTTP/3 → Use HTTP/3 to servers). A host is only tried after one of its responses said it supports HTTP/3, so the first request is always TCP. A network that blocks UDP makes QUIC fail; the host then stays on TCP for 10 minutes.
Layout: nothing to read on iOS#
Simulator.app has to be open on that device, and the program running EmuLabZip has to be allowed in System Settings,
Privacy & Security, Accessibility (the app, or your terminal for emulabzip layout). Wake the device if it shows a
black screen.
Flutter: "Could not find where the Dart VM service listens"#
Only debug and profile builds have one, and the app writes its address to the log once, when it starts. Start the app
again, or give the address from flutter run's output with --uri. A release build has no VM service.
Flutter: the tree has no file names#
The app was not built with --track-widget-creation. flutter run adds it; for flutter build add
--extra-front-end-options=--track-widget-creation.
React Native: "Metro is not running" or "does not list a runtime"#
Start Metro (npx react-native start) and open the app on a device that reaches it (adb reverse tcp:8081 tcp:8081 on
Android). Metro lists a runtime only while the app is connected to it, and lets one debugger in at a time: close React
Native DevTools and Chrome's inspector, then try again. Release builds have no Metro and no React DevTools hook.
State: "RN state is empty" or "no DevTools hook"#
Redux, React Query and contexts are found through React's DevTools hook, which only development builds have. In a release
build register stores in globalThis.__EMULABZIP_STORES__ (see React Native state). A store
used without a react-redux Provider has to be registered too.
State: restoring or saving fails on Android#
The app has to be debuggable (as for Storage). run-as and tar run on the device: an emulator image with
a locked-down run-as cannot save a state. A restore that says the tar was refused found an entry outside the app's
folder; the file is not from EmuLabZip, or is damaged.
Edit: "the table cannot be changed"#
A row is found by rowid or by its primary key. A view, or a table without either, has nothing to tell its rows apart:
change it with SQL in the app instead. An edit that reads back differently puts the old file back and says so.
Devices: an emulator will not start#
emulabzip avd boot needs the SDK's emulator (found from ANDROID_HOME, ANDROID_SDK_ROOT and the usual folders).
Run emulator -avd <name> yourself to see its own message. A running emulator is never wiped or deleted: shut it down
first.
Audit: "the area could not be read"#
The log needs the app to be running, so its lines can be told from the system's: start it and use it, then audit again.
Storage on Android needs a debuggable app, as in Storage. Requests come from the proxy (start it on the
Network view, or pass --har).
Language: "Android changes the language of one app at a time"#
Android has no way to change a device's language from the shell, only an app's (cmd locale set-app-locales, Android 13
and newer). Pass --app, or pick the app in the toolbar. The iOS Simulator changes language for every app, and each takes it
when it starts again.
Text checks: a label is reported that is not cut off#
text-cut-off is a heuristic: a single line whose box was held to the room its container (or the next view in its row)
left, and whose text runs to the end of the box. Check it at 130% and 200%; if it fits, ignore it.
Visual: "the screenshots are not the same size"#
They come from different devices, orientations or display sizes. Compare like with like: the same device, orientation and
display size (control reset-display puts an Android one back).
Network: a Gradle build cannot download its distribution#
Not an EmuLabZip matter, but it comes up with the demo apps: some networks let curl reach the Gradle servers while
Java times out. Download the distribution with curl and put it where Gradle expects it
(~/.gradle/wrapper/dists/<name>/<hash>/), or build with a Gradle you already have.
Layout: Android says uiautomator produced nothing#
Some windows forbid it: secure screens, and a few players. Go to another screen and try again. If the device is busy (a boot animation, an ANR dialog) wait a moment.
Sessions: a recording is left as a .partial folder#
The recording was killed before it could pack itself. Nothing is lost: emulabzip session show run.ezsession.partial
opens it. Delete the folder, or move it, before you record to the same name again.
Timeline: touches are missing#
Touches are read from the kernel's input device with getevent, so a finger on the emulator window or an event sent
through the emulator console is seen. adb shell input tap is injected higher up, inside Android, and is not. iOS does
not give the simulator's touches to anything outside it, so there are none there. Record with --taps.
Timeline: the log times are "estimated"#
The recording was made before EmuLabZip 0.10, or the device could not tell its time, so the log's local times were placed by comparing the first line with the start of the recording. They can be off by the difference between the two clocks. Record again for exact times.
Video: "screenrecord made no video"#
Some screens cannot be recorded (secure windows) and a few images do not support screenrecord at all. The message
carries what the tool printed. On the iOS Simulator, recordVideo needs the simulator to be booted; if it does not start
within 20 seconds, the message says why.
Video: the report has a separate .mp4#
A clip up to 20 MB is part of the HTML file. A bigger one is written next to it as emulabzip-report.mp4, and the file
refers to it by that name: move or attach the two together.
Replay: "not in the recording"#
The app asked for something the recording does not hold: another address, another query, a method that was not used, or
a request that failed when it was recorded. The proxy answers 504 and lists it under Not recorded (or at the end of
emulabzip net --replay). Record again with that request, or add --passthrough to let it reach the server. Matching
ignores the order of query parameters and the port, but not the values: an app that adds a timestamp or a random id to
every request will always miss.
Replay: WebSockets and some connections fail#
While a recording is replayed, what cannot be answered from a HAR file is refused, so it cannot reach the internet:
WebSockets, gRPC calls, apps that do not accept the EmuLabZip certificate, and non-TLS connections the proxy cannot read.
Use --passthrough if those must work.
Traces: "Perfetto did not record a trace"#
Perfetto needs Android 9 or newer. If the message names a permission, restart the emulator, or run
adb shell setprop persist.traced.enable 1 and record again. A custom configuration with a syntax error is reported
by Perfetto itself; check it with adb shell perfetto --txt -c - -o /data/misc/perfetto-traces/test <config.txt.
Traces: a CPU profile fails#
simpleperf only samples apps that are debuggable or profileable, and the app must be running. For the whole system
you need an emulator image that allows adb root (not Google Play). "No samples were recorded" means the app did
nothing while recording: use it, then record again.
Traces: Instruments says Developer Mode is off#
Run sudo DevToolsSecurity -enable in a terminal, enter your password, and record again. DevToolsSecurity -status
shows the current state.
Traces: the download of the trace processor fails#
It comes from github.com/google/perfetto/releases. Behind a proxy, set HTTPS_PROXY. A file that does not match the
pinned SHA-256 is discarded and never run. You can still open any Perfetto trace in the Perfetto UI.
Crashes: nothing is listed#
On Android, the system keeps a crash in DropBox and rate-limits repeats, so a looping app is listed less often than it
crashes. On the iOS Simulator, macOS writes the .ips report a few seconds after the crash, into
~/Library/Logs/DiagnosticReports; reports of apps that are not in a simulator's folder are not listed. Press
Refresh, or run emulabzip crashes.
Crashes: the names are still scrambled#
A mapping is only used for the version of the app it was made for, and the crash says which one that is ("Add the
mapping.txt of com.example 1.2.0 (42)"). Add the file with exactly that version: emulabzip mappings add com.example "1.2.0 (42)" mapping.txt. A file of another build would give wrong names, so it is not used. Frames also stay as they are
when R8 had no line numbers to keep: add -keepattributes SourceFile,LineNumberTable to the rules of the next build.
Crashes: React Native shows 1:608617 instead of a file#
A release build runs a bundle, and its positions need the source map of that bundle. For Hermes use the composed map,
android/app/build/generated/sourcemaps/react/release/index.android.bundle.map, not the packager or compiler ones.
It also has to be the map of the build that crashed.
Crashes: iOS shows bare addresses#
Add the .dSYM of the build that crashed (emulabzip mappings add com.example.app "1.2.0 (42)" MyApp.app.dSYM). Its
UUID has to match the app's, so a dSYM of another build, even of the same version, is not used. Reading addresses needs
a Mac, because it uses atos.
Bug report: no failed requests#
Requests come from the proxy in Network. Start it and connect the device before the bug happens; a report made from a
session recorded with --network has them too.
Controls: the location does nothing on a device#
Only emulators accept a new location, through the emulator console. It needs the token in
~/.emulator_console_auth_token, which the emulator creates the first time it runs from your account. Physical devices
and simulators of other kinds are not supported for location on Android.
Controls: a notification does not appear on Android#
Notifications are posted from the shell with cmd notification post (tried on Android 14). Turn on
notifications for "Android Shell" if the device hides them. The app argument is ignored on Android.
Web pages: my WebView is not listed#
A WebView is listed only when its app calls WebView.setWebContentsDebuggingEnabled(true) (a debug build usually does) and
the page is open. Chrome is listed while it is open. The list is read when you open Frameworks and when you press
Refresh. On iOS use Safari's Develop menu; see Web pages in apps.
Flows: my touches are not recorded#
Only the touchscreen is read: touch the emulator's own window. Taps sent from EmuLabZip (Interact, Play) or by
adb shell input never reach it, and typed text is not recorded. A tap gets the name of the view it hit only when the screen
was read in time, which takes two or three seconds after the touch before; the point is kept either way. See
Input and flows.
Deep links: the check says the domain is not verified#
On Android, ask the device to try again with Verify again or emulabzip link verify <app>, then check after a few
seconds. A fingerprint mismatch usually means the file lists the release key and the build on the device is signed with the
debug key. A domain file that redirects (to www, or from http to https) is refused by both systems. See
Deep links.
Network: a script rule does nothing#
A script runs only after its exact bytes were approved (Approve this script in the rule, or emulabzip script approve).
Change the file and it has to be approved again. If a script runs but the request is unchanged, the flow's details say what
the script wrote or why it failed. See Rule scripts.
Plugins: a plugin cannot be run#
It has to be enabled first, and editing its plugin.json disables it again. A plugin that exits with an error shows the
end of its error output. Check that the program in command exists (it is looked up in the plugin's folder, then on the
PATH) and that it is executable (chmod +x run.sh).
MCP: the assistant sees no tools#
Run emulabzip mcp by hand and send it an initialize request, as in MCP server. If the client
cannot find emulabzip, give it the full path. Standard output carries only the protocol; look at standard error
(EMULABZIP_LOG=debug) for what went wrong.
Getting diagnostics#
Start the app or the CLI with EMULABZIP_LOG=debug and include the output when you
open an issue.