Skip to content

[Bug]: When aborting only first request with {times: 1} from page route then the second request randomly failed #41802

Description

@jesabot-cmyk

Version

1.56.1

Steps to reproduce

  1. Clone my repo at https://github.com/jesabot-cmyk/testPlaywrightIssue
  2. npm install
  3. then npm run test (it will perform 10 runs from playwirght config)
  4. You should see most of runs pass but a few are failing and falling to the hung issue

Here the minimal code to reproduce the bug and figure out what is happening:

import { test, expect } from '@playwright/test';

test('route abort { times: 1 } - 2nd sequential fetch should not be affected', async ({ page }) => {
  await page.goto('/');

  await page.route('**/data', (route) => route.abort('timedout'), { times: 1 });

  const results = await page.evaluate(async () => {
    // Race each fetch against a 3s timeout to distinguish 'hung' from '200' or 'aborted'.
    // 'hung' = { times: 1 } captured the request but never resolved it (orphaned).
    async function fetchOrHung(url: string) {
      const timeout = new Promise<string>(resolve => setTimeout(() => resolve('hung'), 3000));
      const request = fetch(url).then(r => String(r.status)).catch(() => 'aborted');
      return Promise.race([request, timeout]);
    }
    const first = await fetchOrHung('/data');   // awaited — 2nd fetch only starts after 1st completes
    const second = await fetchOrHung('/data');
    return [first, second];
  });

  console.log('results:', results);
  // Expected: ['aborted', '200']
  // Bug:      ['aborted', 'hung']  ← { times: 1 } captured the 2nd request but orphaned it

  expect(results[0]).toBe('aborted');
  expect(results[1]).toBe('200');
});

Expected behavior

Request 1: is caught by the { times: 1 } handler and abort
Requests 2+: is not caught and succeed with status 200

Actual behavior

Request 1: is caught by the { times: 1 } handler and abort
Requests 2+: is caught and fail

Additional context

Random issue so many runs are required to reproduce and observe bug.
Workaround Applied (Stable): Replace { times: 1 } with manual flag-based counting:

let alreadyAborted = false;
await page.route('**/endpoint', async (route) => {
  if (alreadyAborted) {
    return route.continue();
  }
  alreadyAborted = true;
  return route.abort('timedout');
});

This workaround is stable and reliable.

Environment

 System:
    OS: Linux 6.18 Ubuntu 24.04.3 LTS 24.04.3 LTS (Noble Numbat)
    CPU: (32) x64 13th Gen Intel(R) Core(TM) i9-13950HX
    Memory: 19.74 GB / 31.19 GB
    Container: Yes
  Binaries:
    Node: 20.19.5 - /home/sabotje/.nvm/versions/node/v20.19.5/bin/node
    npm: 10.8.2 - /home/sabotje/.nvm/versions/node/v20.19.5/bin/npm
    pnpm: 9.15.9 - /home/sabotje/.nvm/versions/node/v20.19.5/bin/pnpm
  IDEs:
    VSCode: 1.128.1 - /home/sabotje/.vscode-server/bin/5264f2156cbcd7aea5fd004d29eaa10209155d66/bin/remote-cli/code
  Languages:
    Bash: 5.2.21 - /usr/bin/bash
  npmPackages:
    @playwright/test: ^1.56.1 => 1.61.1 

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

browser-chromiumupstreamThis is a bug in something playwright depends on, like a browser.v1.64

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions