From 2d005fcc1c7805cee15a2a16e37fedce854658f4 Mon Sep 17 00:00:00 2001 From: imSp4rky Date: Fri, 21 Aug 2026 17:24:55 -0600 Subject: [PATCH] fix(api): guard two more Windows errno 13 paths in the serve layer --- unshackle/core/api/download_manager.py | 20 +++++++++++++------- unshackle/core/api/handlers.py | 4 +++- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/unshackle/core/api/download_manager.py b/unshackle/core/api/download_manager.py index cbdf1c76..bcda3e73 100644 --- a/unshackle/core/api/download_manager.py +++ b/unshackle/core/api/download_manager.py @@ -1073,13 +1073,19 @@ class DownloadQueueManager: log.debug(f"Worker stderr for job {job.job_id}: {safe_stderr}") result_data: Optional[Dict[str, Any]] = None - try: - with open(result_path, "r", encoding="utf-8") as handle: - result_data = json.load(handle) - except FileNotFoundError: - log.error(f"Result file missing for job {job.job_id}") - except json.JSONDecodeError as exc: - log.error(f"Failed to parse worker result for job {job.job_id}: {exc}") + for attempt in range(5): + try: + with open(result_path, "r", encoding="utf-8") as handle: + result_data = json.load(handle) + except FileNotFoundError: + log.error(f"Result file missing for job {job.job_id}") + except PermissionError as exc: + log.debug(f"Result file for job {job.job_id} denied, retrying: {exc}") + await asyncio.sleep(0.02 * (attempt + 1)) + continue + except json.JSONDecodeError as exc: + log.error(f"Failed to parse worker result for job {job.job_id}: {exc}") + break if returncode != 0: message = result_data.get("message") if result_data else "unknown error" diff --git a/unshackle/core/api/handlers.py b/unshackle/core/api/handlers.py index f45ef93b..de4115fe 100644 --- a/unshackle/core/api/handlers.py +++ b/unshackle/core/api/handlers.py @@ -1861,8 +1861,10 @@ def create_service_instance( cookies.load(ignore_discard=True, ignore_expires=True) finally: import os + from contextlib import suppress - os.unlink(tmp_path) + with suppress(OSError): + os.unlink(tmp_path) else: cookies = dl.get_cookie_jar(normalized_service, profile)