stablyai/orca · error
adb did not return a local scrcpy port
Error message
adb did not return a local scrcpy port
What it means
Thrown by ScrcpyStreamSession.deploy when a dynamic port forward was requested (this.port === 0) but the adb forward output could not be parsed as a finite positive integer. adb is expected to print the allocated local port number to stdout when forwarding to 'tcp:0'; anything else means the forward command misbehaved or the output format changed.
Source
Thrown at src/main/emulator/android/scrcpy-stream-session.ts:113
throw error
}
return session
}
private async deploy(): Promise<void> {
const { runner, sdk, serial, localJarPath } = this.options
ensureAdbOk(
await runner(sdk.adb, pushScrcpyServerArgs(serial, localJarPath, SCRCPY_DEVICE_JAR_PATH)),
'scrcpy server push'
)
const forward = ensureAdbOk(
await runner(sdk.adb, scrcpyForwardArgs(serial, this.port, this.scid)),
'scrcpy port forward'
)
if (this.port === DYNAMIC_FORWARD_PORT) {
const allocated = Number.parseInt(forward.stdout.trim(), 10)
if (!Number.isFinite(allocated) || allocated <= 0) {
throw new Error('adb did not return a local scrcpy port')
}
this.port = allocated
emulatorProbe('scrcpy.forward.port', { serial, port: this.port })
}
}
private spawnServer(): void {
const { sdk, serial, maxSize } = this.options
// The server is long-running, so spawn it directly rather than via the
// request/response command runner.
this.server = spawn(sdk.adb, startScrcpyServerArgs(serial, { scid: this.scid, maxSize }), {
stdio: ['ignore', 'pipe', 'pipe']
})
let serverLog = ''
const capture = (chunk: Buffer): void => {
serverLog += chunk.toString()
}
this.server.stdout?.on('data', capture)View on GitHub (pinned to 1136503c6a)
Solutions
- Update platform-tools to a version whose `adb forward tcp:0 ...` prints the allocated port to stdout.
- Pass an explicit localPort in ScrcpyStreamOptions to skip the dynamic allocation path entirely.
- Run `adb forward --list` and `adb forward tcp:0 tcp:<port>` manually to see what your adb prints and reconcile.
- Restart the adb server if its state is corrupt.
Example fix
// before: dynamic port, adb prints nothing usable
await ScrcpyStreamSession.start({ runner, sdk, serial, localJarPath }, cb)
// after: pin a local port
await ScrcpyStreamSession.start({ runner, sdk, serial, localJarPath, localPort: 27183 }, cb) Defensive patterns
Strategy: fallback
Validate before calling
// Pin a local port to skip dynamic allocation entirely.
const opts: ScrcpyStreamOptions = { runner, sdk, serial, localJarPath, localPort: 27183 } Type guard
function isDynamicPortError(e: unknown): e is Error {
return e instanceof Error && /did not return a local scrcpy port/i.test(e.message)
} Try / catch
try {
return await ScrcpyStreamSession.start(opts, cb)
} catch (e) {
if (isDynamicPortError(e)) {
// fall back to a fixed local port
return await ScrcpyStreamSession.start({ ...opts, localPort: 27183 }, cb)
}
throw e
} Prevention
- Pass an explicit localPort to avoid relying on adb's dynamic-port output format.
- Keep platform-tools current so adb forward tcp:0 prints the allocated port.
- Restart the adb server if forward output is unexpectedly empty.
When it happens
Trigger: ScrcpyStreamSession.start called with no localPort (defaulting to DYNAMIC_FORWARD_PORT=0); the scrcpyForwardArgs adb invocation succeeded (ensureAdbOk passed) but forward.stdout.trim() does not parseInt to a positive number — e.g. empty output, an error string, or a newer adb printing differently.
Common situations: An older or newer adb version with different forward-output formatting; the forward succeeded structurally but printed a status line instead of a port; a locale/format quirk; adb server in an odd state returning empty stdout while exiting 0.
Related errors
- emulator_error
- emulator_error
- emulator_error
- emulator_helper_failed
- scrcpy frame size ${size} exceeds ${MAX_FRAME_BYTES}; stream
AI-assisted analysis of stablyai/orca@1136503c6a (2026-08-12).
Data as JSON: /api/errors/d99afac901c82a9e.
Report an issue: GitHub.