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
- 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.
- Set
retryAttempts: 0 for POST /session; retrying a non-idempotent create doubles the leak and can't succeed inside the same overall deadline anyway.
- 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.
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 customrequestPolicy(packages/provider-webdriver/src/provider-definitions.ts), so there is no flag or env var to raise it (open --timeoutis rejected withINVALID_ARGS).BrowserStack App Automate iOS real-device session creation routinely takes 45–90 s. With a 30 s budget × 2 attempts,
openaborts client-side at ~60 s on most runs. In our testing (iPhone 17 / iOS 26 and iPhone 16 / iOS 18 pools),openfailed 3 of 4 attempts withError (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 /sessionstill completes server-side. Because the client aborted the fetch, it never learns the sessionId and never deletes it; and the automatic retry (retryAttempts: 1on a non-idempotent request) creates a second one. Net effect: every failedopenleaves 2 orphanedrunningsessions 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
Diagnostics show the failing phase is
lease_allocate(request_failed: "The operation was aborted due to timeout").Environment
bs://ref), so upload time is NOT part of the failing window; this is pure session-creation latencySuggested fixes
createSessionits own budget for cloud providers (120–180 s default), or plumbrequestPolicythrough the provider definitions and expose a flag/env override.retryAttempts: 0forPOST /session; retrying a non-idempotent create doubles the leak and can't succeed inside the same overall deadline anyway.Workaround we're using
Patching the installed dist:
timeoutMs:e.requestPolicy?.timeoutMs??3e4→??18e4indist/src/src3.js, then restarting the daemon. With 180 s,opensucceeds reliably (26–38 s observed). We also sweepstatus=runningsessions via the WebDriver hub after any client-side failure.Happy to provide diagnostic NDJSON logs / session IDs privately if useful.