Skip to content

Commit ec419c9

Browse files
committed
fix(fetch): preserve error code in decompression pipeline for retry logic
When a compressed HTTP response (gzip/br/deflate) encounters a network error like ECONNRESET during body streaming, the pipeline error callback and body error handler were wrapping the original error in a new Error, destroying the .code property. The retry logic in _sendRequestWithRetries checks e.code !== 'ECONNRESET' to decide whether to retry, so retries never happened for compressed responses. Fix: check if the error is a network error (ECONNRESET, EPIPE, ECONNABORTED) and pass it through unwrapped so the retry logic can see the code. Only wrap non-network errors as decompression failures.
1 parent b949df5 commit ec419c9

1 file changed

Lines changed: 17 additions & 3 deletions

File tree

  • packages/playwright-core/src/server

packages/playwright-core/src/server/fetch.ts

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -522,10 +522,19 @@ export abstract class APIRequestContext extends SdkObject {
522522
// Brotli and deflate decompressors throw if the input stream is empty.
523523
const emptyStreamTransform = new SafeEmptyStreamTransform(notifyBodyFinished);
524524
body = pipeline(response, emptyStreamTransform, transform, e => {
525-
if (e)
526-
reject(new Error(`failed to decompress '${encoding}' encoding: ${e.message}`));
525+
if (e) {
526+
if (isNetworkConnectionError(e))
527+
reject(e);
528+
else
529+
reject(new Error(`failed to decompress '${encoding}' encoding: ${e.message}`));
530+
}
531+
});
532+
body.on('error', e => {
533+
if (isNetworkConnectionError(e))
534+
reject(e);
535+
else
536+
reject(new Error(`failed to decompress '${encoding}' encoding: ${e}`));
527537
});
528-
body.on('error', e => reject(new Error(`failed to decompress '${encoding}' encoding: ${e}`)));
529538
} else {
530539
body.on('error', reject);
531540
}
@@ -804,6 +813,11 @@ function removeHeader(headers: { [name: string]: string }, name: string) {
804813
delete headers[existing[0]];
805814
}
806815

816+
function isNetworkConnectionError(e: any): boolean {
817+
const code = e?.code;
818+
return code === 'ECONNRESET' || code === 'EPIPE' || code === 'ECONNABORTED';
819+
}
820+
807821
function setBasicAuthorizationHeader(headers: { [name: string]: string }, credentials: HTTPCredentials) {
808822
const { username, password } = credentials;
809823
const encoded = Buffer.from(`${username || ''}:${password || ''}`).toString('base64');

0 commit comments

Comments
 (0)