Repository navigation
Fresh install cannot open the developer tunnel: unpinned pmd-pytcp >=0.1.0 breaks userspace_tunnel (QueueFull flood) #4
Description
GeoShift version
1.5.2 (build 9), commit 3114dd7, built from source via ./Scripts/install_app.sh
macOS, iOS, and iPhone model
macOS 26.7 (25G229, Apple silicon), iOS 27.0 (24A437), iPhone18,4
Connection type
Trusted USB
Reproduction steps
A fresh install never connects. The UI stays on "Restore GPS is waiting for a trusted iPhone connection" and the keeper log fills with asyncio.queues.QueueFull at tens of lines per second — 7,270 entries and roughly 5 MB across the three rotating logs within minutes.
Pairing, trust and lockdown are all fine: the device is USB-attached with Developer Mode on, lockdown info returns the full record, and a Wi-Fi RemotePairing record exists. The failure is one layer lower, in the userspace tunnel. Re-pairing, re-entering the six-digit code, reconnecting the cable and restarting the iPhone all have no effect, which makes sense once the cause is clear.
Root cause: an unpinned transitive dependency. Not GeoShift's own code — but the README's install command is what pulls the broken version, so a new user hits this immediately.
pymobiledevice3 9.31.0 declares no upper bound:
Requires-Dist: pmd-pytcp>=0.0.4
pmd-pytcp turned its API async in 0.1.0 (2026-07-13). pymobiledevice3 9.31.0 was released 2026-06-29 against the synchronous API and still calls it synchronously:
pymobiledevice3/remote/userspace_tunnel.py:201—stack.start()pymobiledevice3/remote/userspace_tunnel.py:239—s.connect((addr, port))
Verified by unpacking each release from PyPI:
| pmd-pytcp | stack/lifecycle.py |
socket/tcp__socket.py |
|---|---|---|
| 0.0.4 – 0.0.6 | def start() |
def connect() |
| 0.1.0 – 0.3.7 | async def start() |
async def connect() |
So the coroutines are created and discarded. The PyTCP stack never starts, the socket never connects, nothing drains the receive queue, the bounded queue fills — and every subsequent frame raises QueueFull, forever. QueueFull is a symptom three steps downstream of the actual defect.
Minimal reproduction, independent of GeoShift:
import asyncio
from pymobiledevice3.remote.userspace_tunnel import UserspaceRsdTunnel
async def main():
t = UserspaceRsdTunnel(serial="<UDID>", autopair=True)
rsd = await asyncio.wait_for(t.aopen(), timeout=30)
print("TUNNEL OK", rsd.udid)
await t.aclose()
asyncio.run(main())Expected behavior
The tunnel opens and the worker connects, as it does once pmd-pytcp is constrained to the version range pymobiledevice3 9.31.0 was written against:
uv tool install --force --python 3.13 'pymobiledevice3==9.31.0' --with 'pmd-pytcp<0.1.0'After this the keeper log shows Connected to iPhone … and Clear command sent successfully, with zero QueueFull.
Suggested for GeoShift: add the constraint to the README quick-install command. The real fix belongs upstream in pymobiledevice3 — either await those call sites or cap pmd-pytcp<0.1.0 — and I am reporting it there as well.
Redacted diagnostics
With pmd-pytcp 0.3.7 (resolved automatically by the documented install):
userspace_tunnel.py:201: RuntimeWarning: coroutine 'start' was never awaited
stack.start()
userspace_tunnel.py:239: RuntimeWarning: coroutine 'TcpSocket.connect' was never awaited
s.connect((addr, port))
RuntimeWarning: coroutine 'TcpSocket.recv' was never awaited
RuntimeWarning: coroutine 'TcpSocket.send' was never awaited
ERROR Exception in callback Queue.put_nowait()
handle: <Handle Queue.put_nowait()>
Traceback (most recent call last):
File ".../asyncio/events.py", line 89, in _run
self._context.run(self._callback, *self._args)
File ".../asyncio/queues.py", line 166, in put_nowait
raise QueueFull
asyncio.queues.QueueFull
... repeating indefinitely
With pmd-pytcp 0.0.4:
TUNNEL OK udid=<redacted>
DVT CHANNEL OK
INFO Connected to iPhone <redacted>
INFO Clear command sent successfully to <redacted>
Secondary observations
-
The error loop is unbounded. It wrote ~5 MB across all three rotating logs in minutes and scrolled away the original context, which made diagnosis considerably harder. Rate-limiting the handler, or bailing out after N consecutive identical failures, would help.
-
The status message is misleading here. "Restore GPS is waiting for a trusted iPhone connection" points at trust and pairing, which were both fine. Distinguishing "no trusted device found" from "tunnel failed to open" would have saved a lot of time.
-
Minor:
MissingValueErroronEnableWifiConnectionsinsideenable_wireless_connections()is caught and logged. Harmless — the connection succeeds right after — but it adds noise to an already noisy log.
Privacy confirmation
- I removed device identifiers, IP addresses, personal paths, pairing records, and credentials.
- This is not a security vulnerability or private report.
Activity
Lemelson commentedon Oct 8, 2026
Thanks for the detailed report. I independently verified the dependency incompatibility and prepared a focused fix in b313f12, tracked in draft PR #5.
The original install/test command resolved pmd-pytcp 0.3.7 in a clean Python 3.13 environment. New regression checks failed on its version and real async stack/TCP/UDP methods. All installation and test instructions and Python CI now constrain
pmd-pytcp>=0.0.4,<0.1.0alongsidepymobiledevice3==9.31.0.Verification completed:
uv run, isolateduv tool install, and freshpipvenv all resolved pmd-pytcp 0.0.6 and passed all 21 Python tests, including the new dependency/API regression.pip check, 21 Swift tests, packaging, signature verification, and local main-screen/Settings launch passed. The GUI used the Mac's existing compatible 0.0.4 backend.For an affected uv installation, the documented repair is:
Then select Restart in GeoShift.
I also checked the secondary observations. The rapid QueueFull flood originates in upstream relay callbacks when synchronous
recvreceives a coroutine; the reconnect delay cannot rate-limit those callbacks. The bound removes that incompatibility. General error deduplication and the restore UI's masking of tunnel errors remain separate improvements; pending GPS-clear retries are preserved.Physical-iPhone acceptance is still pending: no USB phone was connected and the saved Wi-Fi connection probe timed out. These checks confirm the dependency fix, not an actual GPS change. PR #5 remains draft, this issue remains open, and no new build has been published until tunnel/Start/Restore/reconnect and location verification on an iPhone are completed.