stablyai/orca · error · EmulatorError

emulator_no_active

emulator_no_active

Error message

No active emulator stream for gesture input

What it means

Thrown by IosEmulatorBackend.gesture when wsUrl is null/empty. The iOS gesture path requires an active WebSocket stream (wsUrl) from the registry, supplied by an attached simulator session; without it there is no channel to deliver the gesture sequence. The backend cannot synthesize a stream, so it throws rather than no-op.

Source

Thrown at src/main/emulator/backends/ios-emulator-backend.ts:153

    }
    return { available: true, devices, message: 'Ready' }
  }

  async tap(deviceId: string, x: number, y: number): Promise<void> {
    const udid = await this.resolveDeviceId(deviceId)
    await this.execServeSim(['tap', x.toString(), y.toString(), '-d', udid])
  }

  async gesture(
    _deviceId: string,
    points: EmulatorGesturePoint[],
    wsUrl: string | null
  ): Promise<void> {
    if (points.length === 0) {
      return
    }
    if (!wsUrl) {
      throw new EmulatorError('emulator_no_active', 'No active emulator stream for gesture input')
    }
    await sendEmulatorGestureSequence(wsUrl, points)
  }

  async type(deviceId: string, text: string): Promise<void> {
    const udid = await this.resolveDeviceId(deviceId)
    await this.execServeSim(['type', text, '-d', udid])
  }

  async button(deviceId: string, name: string): Promise<void> {
    const udid = await this.resolveDeviceId(deviceId)
    await this.execServeSim(['button', name, '-d', udid])
  }

  async rotate(deviceId: string, orientation: string): Promise<void> {
    const udid = await this.resolveDeviceId(deviceId)
    await this.execServeSim(['rotate', orientation, '-d', udid])
  }

View on GitHub (pinned to 1136503c6a)

Solutions

  1. Call startSession(deviceId) first and thread its returned wsUrl into subsequent gesture calls.
  2. If the session was detached, re-attach (start a new session) before issuing gestures.
  3. Guard the call: skip gestures when wsUrl is falsy rather than passing null through.
  4. Verify the iOS backend's session registry is populated for the target simulator.

Example fix

// before: gesture with no active stream
await iosBackend.gesture(udid, points, null)
// after: attach a session, use its wsUrl
const session = await iosBackend.startSession(udid)
await iosBackend.gesture(udid, points, session.wsUrl)
Defensive patterns

Strategy: validation

Validate before calling

// Guard gesture calls against a missing stream URL.
function hasStream(wsUrl: string | null): wsUrl is string {
  return !!wsUrl && wsUrl !== ''
}

Type guard

import { EmulatorError } from '../emulator-errors'
function isNoActiveStream(e: unknown): e is EmulatorError {
  return e instanceof EmulatorError && e.code === 'emulator_no_active'
}

Try / catch

if (!hasStream(wsUrl)) {
  const session = await iosBackend.startSession(deviceId)
  wsUrl = session.wsUrl
}
await iosBackend.gesture(deviceId, points, wsUrl)

Prevention

When it happens

Trigger: gesture(deviceId, points, wsUrl) called with wsUrl null or empty AND points.length > 0 (the empty-points case returns early). wsUrl comes from an attached serve-sim detached session; if no session is attached, the caller has no wsUrl to pass.

Common situations: Calling gesture before startSession has established the detached serve-sim helper (which provides the wsUrl); the simulator session was closed/detached and the registry cleared the wsUrl; attempting gestures on a simulator that was never attached; a routing bug passing null where the registry URL should be.

Related errors


AI-assisted analysis of stablyai/orca@1136503c6a (2026-08-12). Data as JSON: /api/errors/d4b714a27290edd7. Report an issue: GitHub.