Skip to content

[Bug] All protocol calls can block indefinitely: timeouts are enforced on the driver side, so a frozen driver/browser process never surfaces TimeoutError #1990

Description

@disheno

[Bug] All protocol calls can block indefinitely: timeouts are enforced on the driver side, so a frozen driver/browser process never surfaces TimeoutError

Summary

In a production screenshot microservice (Playwright Java embedded in a Spring Boot app, 10 worker threads, each with its own thread-confined Playwright/Browser/Page chain), all 10 worker threads blocked indefinitely inside waitForFunction for 16+ hours, despite each call setting setTimeout(6000). A thread dump showed every thread parked in PipeTransport.poll → ArrayBlockingQueue.poll, waiting for messages from the driver that never arrive. There were no errors, no page events, and no pipe EOF — just silence.

"chartProcessor-1" ... java.lang.Thread.State: TIMED_WAITING (parking)
	at java.util.concurrent.locks.LockSupport.parkNanos(...)
	at java.util.concurrent.ArrayBlockingQueue.poll(ArrayBlockingQueue.java:435)
	at com.microsoft.playwright.impl.PipeTransport.poll(PipeTransport.java:68)
	at com.microsoft.playwright.impl.Connection.processOneMessage(Connection.java:205)
	at com.microsoft.playwright.impl.ChannelOwner.runUntil(ChannelOwner.java:130)
	at com.microsoft.playwright.impl.Connection.sendMessage(Connection.java:130)
	at com.microsoft.playwright.impl.ChannelOwner.sendMessage(ChannelOwner.java:118)
	at com.microsoft.playwright.impl.FrameImpl.waitForFunctionImpl(FrameImpl.java:877)
	...

Root cause (from decompiled bytecode, 1.52.0)

  • FrameImpl.waitForFunctionImpl is a single synchronous sendMessage("waitForFunction", json); the timeout option is only serialized into the protocol message. There is no client-side deadline.
  • ChannelOwner.runUntil loops while (!waitable.isDone()) connection.processOneMessage() — no deadline check in the loop.
  • Connection.processOneMessage calls transport.poll(Duration.ofMillis(10)) and simply waits for the next driver message.
  • The configured timeout is enforced on the Node driver side (e.g. progress.js in the bundled driver). When the driver process itself — or the browser process it talks to — hangs (in our case, consistent with container-level resource pressure freezing all driver + browser child processes at the same moment), no message is ever produced, the driver-side timers never fire, and every pending protocol call blocks forever.

Note that all threads had fully independent Playwright/Browser/Page chains (per-thread confinement, no sharing), and all of them froze simultaneously — which is how we concluded this was an environment-level event rather than an application bug. Even so, the library turning that into a permanent, silent hang of the host application is a robustness problem on the Java client side.

Impact

Any driver/browser freeze converts into a permanent hang of calling threads; all configured timeouts become meaningless in this state. For services embedding Playwright in production (rather than test usage), this is severe: worker pools fill up, queues backpressure, and the service stops processing entirely.

Related issues

Suggested improvement

Enforce a client-side deadline in ChannelOwner.runUntil / Connection.processOneMessage: track the per-call deadline, and when a poll returns nothing past the deadline, throw TimeoutError locally (optionally with a distinct message such as "driver did not respond"). This would make the Java client consistent with other language clients, where timeout enforcement is in-process, and would make driver/browser hangs observable and recoverable instead of silently fatal.

Environment

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions