Skip to content

fix(core): fix race condition in waitForFunctionExpression() - #41706

Merged
Yury Semikhatsky (yury-s) merged 1 commit into
microsoft:mainfrom
hbenl:fix-waitforfunction
Jul 10, 2026
Merged

fix(core): fix race condition in waitForFunctionExpression()#41706
Yury Semikhatsky (yury-s) merged 1 commit into
microsoft:mainfrom
hbenl:fix-waitforfunction

Conversation

@hbenl

@hbenlHolger Benl (hbenl) commented Jul 9, 2026

Copy link
Copy Markdown
Collaborator

I ran into a subtle race condition in Frame.waitForFunctionExpression() (see #41637 (comment)):
If the operation is aborted during injectedScript.evaluateHandle() (after it sent the evaluation to the browser but before it receives the result), the loop that it sets up in the browser is never aborted.
This PR fixes the issue by removing the progress.race() wrapper around injectedScript.evaluateHandle() and checking progress.signal.aborted afterwards instead, ensuring that the catch block that aborts the loop is executed in this case.
I thought about using raceUncancellableOperationWithCleanup() instead but it doesn't await the cleanup function before throwing.

Comment threadpackages/playwright-core/src/server/frames.ts Outdated
@github-actions

This comment has been minimized.

@yury-s

Copy link
Copy Markdown
Member

Dmitry Gozman (@dgozman) can you have a look?

const context = world === 'main' ? await progress.race(this.mainContext()) : await progress.race(this.utilityContext());
const injectedScript = await progress.race(context.injectedScript());
const handle = await progress.race(injectedScript.evaluateHandle((injected, { expression, isFunction, polling, arg }) => {
const handle = await injectedScript.evaluateHandle((injected, { expression, isFunction, polling, arg }) => {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think raceUncancellableOperationWithCleanup is the way. We have to race this evaluateHandle call, otherwise it may stall forever due to a stalling navigation.

@github-actions

Copy link
Copy Markdown
Contributor

Test results for "MCP"

7760 passed, 1249 skipped


Merge workflow run.

@github-actions

Copy link
Copy Markdown
Contributor

Test results for "tests 1"

4 flaky⚠️ [chromium-library] › library/beforeunload.spec.ts:130 › should support dismissing the dialog multiple times `@chromium-ubuntu-22.04-arm-node20`
⚠️ [chromium-library] › library/video.spec.ts:717 › screencast › should work with video+trace `@chromium-ubuntu-22.04-arm-node20`
⚠️ [chromium-library] › library/video.spec.ts:717 › screencast › should work with video+trace `@chromium-ubuntu-22.04-node20`
⚠️ [chromium-library] › library/video.spec.ts:476 › screencast › should capture static page in persistent context Radoslav Kirilov (@smoke) `@chromium-ubuntu-22.04-node22`

49520 passed, 1161 skipped


Merge workflow run.

@yury-s
Yury Semikhatsky (yury-s) merged commit ba4a093 into microsoft:mainJul 10, 2026
48 checks passed
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@hbenl@yury-s@dgozman