Skip to content

Concurrent agent-device CLI processes on one host cross-contaminate BrowserStack session/lease/device state #1659

Description

@TilakVattikuti

Summary

Running multiple independent agent-device CLI processes concurrently from the same host, each targeting a different BrowserStack device via its own freshly-minted connect --json session id (no shared --session/--config between them), causes local daemon state under ~/.agent-device/ to leak across processes — sessions end up bound to the wrong physical device, sometimes silently.

Repro

3 independent processes on the same macOS host, no shared shell state, each running:

agent-device connect browserstack --platform ios --device "<distinct device>" \
  --provider-os-version <distinct> --provider-app bs://<app-id> --force --json
# parse data.session
agent-device open <bundle-id> --session "$SESSION_NAME"
# ... normal commands ...
agent-device close --session "$SESSION_NAME"; agent-device disconnect --session "$SESSION_NAME"

Devices used: iPhone 15 Pro/iOS 17, iPhone 16 Pro/iOS 18, iPad Pro 11 2025/iOS 26.

Observed corruption (concrete evidence, one per process)

  • Process A (iPhone 15 Pro): its local remote-connection JSON was silently rewritten mid-run to reference iPad Pro 11 2025's config; a later session name it was given also ended up bound to iPhone 16 Pro — both exactly the other two processes' target devices.
  • Process B (iPhone 16 Pro): repeated Error (INVALID_ARGS): lease_allocate is already bound to session "browserstack:X" on apple device "iPhone 16 Pro" (...), but this request selected --device=iPad Pro 11 2025 and Error (UNAUTHORIZED): Lease does not match session owner (leaseId). One connect call returned a session name literally containing ipadpro11 in response to a request for iPhone 16 Pro. A local daemon crash (Replacing daemon (pid ..., v0.20.5): unreachable) also occurred mid-run, wiping session state.
  • Process C (iPad Pro 11 2025): connect/open silently fell back to a local Apple Simulator instead of the requested BrowserStack device (xcrun exited 4, "app bundle is not installed on this simulator"), and hit UNAUTHORIZED: Lease is not active even though BrowserStack's own dashboard showed the session "ready". daemon stop / daemon stop --clean did not resolve it; explicit --tenant/--run-id isolation flags did not either. The only working mitigation found was forcing a fully unique session name via the (undocumented, env-var-only) AGENT_DEVICE_SESSION variable.

Impact

Two people, or two CI jobs, running agent-device against BrowserStack from the same machine/runner at the same time can silently interfere with each other's sessions and end up issuing commands against the wrong device — a correctness issue, not just flakiness, and potentially a confidentiality concern in shared CI infrastructure.

Note on existing coverage

#1439's concurrency torture lane validates SessionStore/LeaseRegistry invariants via an in-process deterministic scheduler (simulated interleavings within one Node process). That doesn't appear to exercise this failure mode, which is multiple separate OS processes racing on shared on-disk daemon state under ~/.agent-device/, not in-process async interleaving.

Environment

  • agent-device 0.20.5, macOS host, BrowserStack App Automate
  • 3 concurrent independent CLI processes, each targeting a different iOS device, no intentional shared state

Ask

Root-cause + fix for cross-process isolation of BrowserStack session/lease/device-claim state under genuine OS-level concurrency, and/or first-class documentation (not just an undocumented env var) if full isolation isn't immediately feasible.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions