From 75fffc1e2508db2b6c44bf311ef57c27182768b3 Mon Sep 17 00:00:00 2001 From: Will Miao Date: Fri, 26 Jun 2026 14:32:43 +0800 Subject: [PATCH] fix(aria2): move stderr drain after _wait_until_ready to avoid swallowing startup errors _drain_stderr and _wait_until_ready both read from the same stderr pipe. Starting the drain task before _wait_until_ready creates a race where the drain task consumes aria2's early-exit error message before the startup waiter can read it, resulting in an empty error message in the logs. Also confirmed that --fsync does not exist as an aria2 option (exit code 28 = Invalid argument). --- py/services/aria2_downloader.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/py/services/aria2_downloader.py b/py/services/aria2_downloader.py index 145d5e2e..6a7eb66e 100644 --- a/py/services/aria2_downloader.py +++ b/py/services/aria2_downloader.py @@ -520,16 +520,19 @@ class Aria2Downloader: stderr=asyncio.subprocess.PIPE, ) + await self._wait_until_ready() + # Drain aria2's stderr in a background task so the pipe buffer # never fills up. If the pipe blocks, aria2 itself freezes and # cannot respond to RPC — this was the root cause of the # "Failed to query aria2 download status" timeout bug. + # Must start AFTER _wait_until_ready to avoid a race where the + # drain task consumes aria2's early-exit error message before + # _wait_until_ready can read it. self._stderr_reader_task = asyncio.create_task( self._drain_stderr() ) - await self._wait_until_ready() - def _resolve_executable(self) -> str: settings = get_settings_manager() configured_path = (settings.get("aria2c_path") or "").strip()