proton-core's auto transport races alternative routing: third-party DoH probes and leaked-task tracebacks #164

Open
opened 2026-08-24 20:29:41 -04:00 by mysticalsoap · 0 comments
Owner

A scheduled ProtonVPN renewal whose refresh() round-trip ran long dumped a full aiohttp traceback plus four Task was destroyed but it is pending! errors into the service log — while the import itself succeeded seconds later.

Cause: proton-core's default AutoTransport races AiohttpTransport (delay 0) against AlternativeRoutingTransport (delay 5s). Any API call slower than 5s starts the alternative-routing racer, which discovers Proton's fallback domains by sending DoH queries to hardcoded Google DNS (8.8.4.4/8.8.8.8 + v6) and Quad9 resolvers. On a v6-less network the v6 probe raises, the primary transport wins, and the abandoned racer tasks surface through asyncio's exception handler as ERROR tracebacks when the loop closes.

Two problems: the scary-looking noise, and a root service phoning Google/Quad9 DNS whenever Proton's API is momentarily slow — traffic nothing in aqomui asked for.

Fix: pin session.transport_factory = AiohttpTransport on every session the provider builds — that is auto's primary transport, minus the racer. Trade-off: on a network where Proton's API is blocked, an import fails with the normal network error instead of possibly succeeding via alternative routing; acceptable here, and the task leak itself is an upstream python-proton-core bug either way.

🤖 Generated with Claude Code

A scheduled ProtonVPN renewal whose `refresh()` round-trip ran long dumped a full aiohttp traceback plus four `Task was destroyed but it is pending!` errors into the service log — while the import itself succeeded seconds later. Cause: proton-core's default `AutoTransport` races `AiohttpTransport` (delay 0) against `AlternativeRoutingTransport` (delay 5s). Any API call slower than 5s starts the alternative-routing racer, which discovers Proton's fallback domains by sending DoH queries to hardcoded Google DNS (8.8.4.4/8.8.8.8 + v6) and Quad9 resolvers. On a v6-less network the v6 probe raises, the primary transport wins, and the abandoned racer tasks surface through asyncio's exception handler as ERROR tracebacks when the loop closes. Two problems: the scary-looking noise, and a root service phoning Google/Quad9 DNS whenever Proton's API is momentarily slow — traffic nothing in aqomui asked for. Fix: pin `session.transport_factory = AiohttpTransport` on every session the provider builds — that is auto's primary transport, minus the racer. Trade-off: on a network where Proton's API is blocked, an import fails with the normal network error instead of possibly succeeding via alternative routing; acceptable here, and the task leak itself is an upstream python-proton-core bug either way. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
Sign in to join this conversation.
No milestone
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
mysticalsoap/aqomui#164
No description provided.