microsoft/playwright · error · Error

Malformed endpoint. Did you use Android.launchServer method?

Error message

Malformed endpoint. Did you use Android.launchServer method?

What it means

Thrown during Android.connect() when the remote endpoint initializes Playwright but the initializer has no preConnectedAndroidDevice. The connect flow expects the endpoint to be an Android server that pre-attaches a device; absence of that field means the endpoint was not started via an Android launcher. The connection is closed before throwing.

Source

Thrown at packages/playwright-core/src/client/android.ts:86

  }

  async connect(endpoint: string, options: Parameters<api.Android['connect']>[1] = {}): Promise<api.AndroidDevice> {
    return await this._wrapApiCall(async () => {
      const deadline = options.timeout ? monotonicTime() + options.timeout : 0;
      const headers = { 'x-playwright-browser': 'android', ...options.headers };
      const connectParams: channels.LocalUtilsConnectParams = { endpoint, headers, slowMo: options.slowMo };
      const connection = await connectToEndpoint(this._connection, connectParams, { signal: undefined, timeout: options.timeout || 0 });

      let device: AndroidDevice;
      connection.on('close', () => {
        device?._didClose();
      });

      const result = await raceAgainstDeadline(async () => {
        const playwright = await connection!.initializePlaywright();
        if (!playwright._initializer.preConnectedAndroidDevice) {
          connection.close();
          throw new Error('Malformed endpoint. Did you use Android.launchServer method?');
        }
        device = AndroidDevice.from(playwright._initializer.preConnectedAndroidDevice!);
        device._shouldCloseConnectionOnClose = true;
        device.on(Events.AndroidDevice.Close, () => connection.close());
        return device;
      }, deadline);
      if (!result.timedOut) {
        return result.result;
      } else {
        connection.close();
        throw new Error(`Timeout ${options.timeout}ms exceeded`);
      }
    });
  }
}

export class AndroidDevice extends ChannelOwner<channels.AndroidDeviceChannel> implements api.AndroidDevice {
  readonly _timeoutSettings: TimeoutSettings;

View on GitHub (pinned to c8fc3bf8d3)

Solutions

  1. Ensure the endpoint was produced by an Android-capable server (Android driver running on the host).
  2. Verify the wsEndpoint value and that the server process is the Android variant.
  3. Use BrowserType.connectOverCDP/connect for non-Android endpoints instead.

Example fix

// before
const device = await android.connect('ws://host:9222/non-android-endpoint');
// after
const device = await android.connect('ws://android-host:9999/android-ws');
Defensive patterns

Strategy: validation

Validate before calling

// Ensure the endpoint is an Android server before connecting
if (!/android/i.test(endpoint))
  console.warn('Endpoint may not be an Android server; connect may fail with malformed-endpoint.');

Try / catch

try {
  const device = await android.connect(endpoint, { timeout: 30000 });
} catch (e) {
  if ((e as Error).message.includes('Malformed endpoint'))
    throw new Error(`Endpoint ${endpoint} is not an Android server.`);
  throw e;
}

Prevention

When it happens

Trigger: Calling `android.connect(wsEndpoint)` where wsEndpoint points to a regular chromium BrowserType.launchServer endpoint, or any non-Android WS server. The raceAgainstDeadline resolves, but playwright._initializer.preConnectedAndroidDevice is falsy.

Common situations: Reusing a wsEndpoint captured from `chromium.launchServer()` for an Android connect call; pointing at a stale or wrong-service URL; version mismatch between server (non-Android build) and Android client.

Understand the failure class

Related errors


AI-assisted analysis of microsoft/playwright@c8fc3bf8d3 (2026-08-12). Data as JSON: /api/errors/c0663a5e6fc3d77c. Report an issue: GitHub.