From 208f4f3d78b15f68d9b17e78f5318c0e2ceb26de Mon Sep 17 00:00:00 2001 From: devlikepro Date: Sat, 27 Jun 2026 16:42:27 +0700 Subject: [PATCH] =?UTF-8?q?[core]=20GOWS=20-=20fix=20document=20media=20?= =?UTF-8?q?=E2=80=94=20403=20on=20live=20media=20+=20media-retry=20never?= =?UTF-8?q?=20completes/refreshes=20directPath=20-=20fix=20##2131?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/core/engines/gows/session.gows.core.ts | 19 +++++++++++++++++++ src/core/media/MediaManager.ts | 9 ++++++++- 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/src/core/engines/gows/session.gows.core.ts b/src/core/engines/gows/session.gows.core.ts index 346284dd..fafe7e52 100644 --- a/src/core/engines/gows/session.gows.core.ts +++ b/src/core/engines/gows/session.gows.core.ts @@ -2958,6 +2958,19 @@ export class WhatsappSessionGoWSCore extends WhatsappSession { } } +/** + * gRPC status codes returned by GOWS DownloadMedia that represent a definitive + * failure (the media cannot be fetched right now and retrying won't help). Used + * to tag the error as non-retriable so MediaManager doesn't re-issue the call. + */ +const NON_RETRIABLE_DOWNLOAD_MEDIA_CODES: Set = new Set([ + grpc.status.FAILED_PRECONDITION, + grpc.status.NOT_FOUND, + grpc.status.INVALID_ARGUMENT, + grpc.status.PERMISSION_DENIED, + grpc.status.UNIMPLEMENTED, +]); + /** * Many encrypted stickers carry URL "https://a.whatsapp.net" with no path. If * that string is passed to DownloadMedia, the Go client may attempt HTTP GET to @@ -3062,6 +3075,12 @@ export class GOWSEngineMediaProcessor implements IMediaEngineProcessor { } catch (err) { if (err?.code === grpc.status.DEADLINE_EXCEEDED) { err.message = `DownloadMedia timed out after ${mediaDownloadTimeoutMs}ms for message '${message?.Info?.ID}'`; + } else if (NON_RETRIABLE_DOWNLOAD_MEDIA_CODES.has(err?.code)) { + // The media is not currently downloadable (e.g. CDN 403 after the + // anonymous + media-retry fallbacks, or the object is gone). Retrying + // the gRPC call won't help and each attempt can block on a media-retry + // wait, so mark it so MediaManager stops retrying. + err.nonRetriable = true; } throw err; } diff --git a/src/core/media/MediaManager.ts b/src/core/media/MediaManager.ts index e829d46a..c3e2b3ab 100644 --- a/src/core/media/MediaManager.ts +++ b/src/core/media/MediaManager.ts @@ -187,7 +187,14 @@ export class MediaManager implements IMediaManager { const retryOptions = this.RETRY_OPTIONS; try { return await promiseRetry((retry: CallableFunction, number: number) => { - return fn().catch(retry); + return fn().catch((err: any) => { + // Some failures are definitive (e.g. media not downloadable): retrying + // won't help and may block, so abort the retry loop immediately. + if (err?.nonRetriable) { + throw err; + } + return retry(err); + }); }, retryOptions); } catch (error) { this.log.error(