Skip to content

Bug: PlaywrightConfig::timeoutMs not propagated to ProcessJsonRpcClient — RPC requests always time out at 30 s #92

@jarkkombrain

Description

@jarkkombrain

File: src/Transport/JsonRpc/JsonRpcTransport.php

Description

I was successfully able to launch chromium & webkit. But Firefox always failed to: playwright firefox JSON-RPC request 1 timed out

PlaywrightConfig accepts a timeoutMs parameter that is documented as controlling the timeout for browser operations. It is correctly used to set the Symfony Process timeout (how long the Node subprocess may run). However, it is not passed to ProcessJsonRpcClient, which has its own separate defaultTimeoutMs that is hardcoded to 30000.0 ms.

This means any individual RPC request — including browser.launch() — will time out after 30 seconds regardless of what timeoutMs is set to. Increasing timeoutMs in PlaywrightConfig has no effect on actual request timeouts.

Steps to reproduce

// Firefox launch can take >30 s in server environments.
// Setting timeoutMs: 90000 should give 90 s for each operation.
$config  = new PlaywrightConfig(timeoutMs: 90000);
$client  = PlaywrightFactory::create($config);
$browser = $client->firefox()->withHeadless(true)->launch(); // always throws after 30 s

Playwright\Exception\NetworkException: JSON-RPC request 1 timed out after 30000ms

Root cause

In JsonRpcTransport::connect(), ProcessJsonRpcClient is constructed with a hardcoded timeout:

// src/Transport/JsonRpc/JsonRpcTransport.php

$this->process = $this->processLauncher->start(
    $command,
    $cwd,
    $env,
    is_int($timeout) ? (float) $timeout : $timeout   // ← process timeout uses config correctly
);

$this->client = new ProcessJsonRpcClient(
    process: $this->process,
    processLauncher: $this->processLauncher,
    logger: $this->logger,
    defaultTimeoutMs: 30000.0,                        // ← hardcoded, ignores $config->timeoutMs
);

The $timeout variable (derived from $this->config['timeout'], which comes from PlaywrightConfig::timeoutMs / 1000) is available in scope at this point but is not forwarded.

Fix

$this->client = new ProcessJsonRpcClient(
    process: $this->process,
    processLauncher: $this->processLauncher,
    logger: $this->logger,
    defaultTimeoutMs: null !== $timeout ? (float) ($timeout * 1000) : 30000.0,
);

This uses the configured timeout when one is provided and falls back to the existing 30 s default otherwise — fully backwards compatible.


Why this matters

Slow browser engines (particularly Firefox on first launch in restricted server environments) can take significantly longer than 30 s to initialise. There is currently no way to work around this through the public API — PlaywrightConfig(timeoutMs: 90000) appears to be the correct knob to turn, but it has no effect on the operation that actually times out.

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