Skip to content

Cloud WebDriver session creation runs under the generic 30s request policy — BrowserStack iOS open fails ~75% of the time and leaks billed provider sessions #1774

Description

@rogerfuentes

Summary

WebDriverClient.createSession() (POST /session) executes under the generic request policy; timeoutMs ?? 30_000, retryAttempts ?? 1 (packages/provider-webdriver/src/webdriver-client.ts:96); and the provider definitions never pass a custom requestPolicy (packages/provider-webdriver/src/provider-definitions.ts), so there is no flag or env var to raise it (open --timeout is rejected with INVALID_ARGS).

BrowserStack App Automate iOS real-device session creation routinely takes 45–90 s. With a 30 s budget × 2 attempts, open aborts client-side at ~60 s on most runs. In our testing (iPhone 17 / iOS 26 and iPhone 16 / iOS 18 pools), open failed 3 of 4 attempts with Error (UNKNOWN): The operation was aborted due to timeout; the single success completed in 59.985 s, inside the window by 15 ms.

The compounding defect: leaked billed sessions

Each timed-out POST /session still completes server-side. Because the client aborted the fetch, it never learns the sessionId and never deletes it; and the automatic retry (retryAttempts: 1 on a non-idempotent request) creates a second one. Net effect: every failed open leaves 2 orphaned running sessions on BrowserStack, billing device minutes until BrowserStack's own idle timeout (~90 s) reaps them. Across a short debugging session we accumulated 6+ leaked sessions. They can only be stopped via the WebDriver hub (DELETE /wd/hub/session/<id>) since BrowserStack's REST API refuses to delete running sessions.

Repro

export BROWSERSTACK_USERNAME=... BROWSERSTACK_ACCESS_KEY=...
agent-device connect browserstack \
  --platform ios --device "iPhone 17" --provider-os-version 26 \
  --provider-app bs://<uploaded-ipa>
agent-device open com.example.app --relaunch
# → ~75% of runs: Error (UNKNOWN): The operation was aborted due to timeout (after ~60s)
# BrowserStack dashboard: 2 new sessions in status "running" per failed open

Diagnostics show the failing phase is lease_allocate (request_failed: "The operation was aborted due to timeout").

Environment

  • agent-device 0.20.8 (also relevant to v0.20.7)
  • Node v22.22.2, macOS (darwin 25.2.0)
  • BrowserStack App Automate, iOS real devices (iPhone 17/26.x, iPhone 16/18.x)
  • App: ~130 MB IPA, pre-uploaded via REST (bs:// ref), so upload time is NOT part of the failing window; this is pure session-creation latency

Suggested fixes

  1. Give createSession its own budget for cloud providers (120–180 s default), or plumb requestPolicy through the provider definitions and expose a flag/env override.
  2. Set retryAttempts: 0 for POST /session; retrying a non-idempotent create doubles the leak and can't succeed inside the same overall deadline anyway.
  3. On client-side abort of a create, attempt cleanup: query the provider REST API for sessions created under this build/label and delete strays, or at minimum surface a warning that a billed session may have been left running.

Workaround we're using

Patching the installed dist: timeoutMs:e.requestPolicy?.timeoutMs??3e4 → ??18e4 in dist/src/src3.js, then restarting the daemon. With 180 s, open succeeds reliably (26–38 s observed). We also sweep status=running sessions via the WebDriver hub after any client-side failure.

Happy to provide diagnostic NDJSON logs / session IDs privately if useful.

Activity

  1. thymikee commented on Aug 14, 2026

    @thymikee
    Member

    Confirmed against current main: WebDriverClient.createSession() inherits the generic 30s timeout and one retry, while the BrowserStack provider definition supplies no request-policy override. The reported failure/leak class is therefore credible and high impact. Marking needs-triage rather than ready-for-agent because the owning policy still needs a maintainer decision: use a phase/provider-specific session-creation budget (and decide whether it has a supported override surface), make non-idempotent POST /session explicitly zero-retry, and define cancellation/ownership evidence without assuming heuristic REST cleanup of unknown sessions. Once those acceptance choices are recorded, this should be straightforward to hand to an agent with planted transport regressions for timeout, zero retry, and late provider completion.

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

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions