microsoft/playwright · error · ValidationError
${path}: expected channel ${names.toString()}
Error message
${path}: expected channel ${names.toString()} What it means
Thrown by _tChannelImplFromWire when the referenced object exists in _objects but its _type is not in the allowed names list (and names !== '*'). The server sent an object handle where a specific channel type was expected, but the handle's actual type differs — a protocol contract violation on the wire.
Source
Thrown at packages/playwright-core/src/client/connection.ts:307
}
close(cause?: string) {
if (this._closedError)
return;
this._closedError = new TargetClosedError(cause);
for (const callback of this._callbacks.values())
callback.reject(this._closedError);
this._callbacks.clear();
this.emit('close');
}
private _tChannelImplFromWire(names: '*' | string[], arg: any, path: string, context: ValidatorContext) {
if (arg && typeof arg === 'object' && typeof arg.guid === 'string') {
const object = this._objects.get(arg.guid)!;
if (!object)
throw new Error(`Object with guid ${arg.guid} was not bound in the connection`);
if (names !== '*' && !names.includes(object._type))
throw new ValidationError(`${path}: expected channel ${names.toString()}`);
return object._channel;
}
throw new ValidationError(`${path}: expected channel ${names.toString()}`);
}
private _createRemoteObject(parentGuid: string, type: string, guid: string, initializer: any): any {
const parent = this._objects.get(parentGuid);
if (!parent)
throw new Error(`Cannot find parent object ${parentGuid} to create ${guid}`);
const validator = findValidator(type, '', 'Initializer');
initializer = validator(initializer, '', this._validatorFromWireContext());
const factory = this._objectFactories.get(type);
if (!factory)
throw new Error('Missing type ' + type);
return factory(parent, type, guid, initializer);
}
}
View on GitHub (pinned to c8fc3bf8d3)
Solutions
- Match client and server Playwright versions.
- If running a patched server, verify it returns the correct object type for each channel-typed field per protocol.yml.
- Reproduce with DEBUG=pw:channel and confirm the offending field and the actual type received.
Defensive patterns
Strategy: validation
Try / catch
try {
await page.someApiCallReturningObject();
} catch (e) {
if (/expected channel/.test(String(e?.message))) {
// Server returned the wrong object type — almost always a version mismatch.
throw new Error('Client/server Playwright version mismatch: ' + e.message);
}
throw e;
} Prevention
- Lock client and server to the same Playwright release.
- Don't run patched servers that change channel field types.
- Add a version-handshake check on startup.
When it happens
Trigger: A method/event parameter validated as e.g. 'Page' or 'Frame' carries a guid whose object is a different type (Browser, Request, etc.). Indicates a server bug, version skew, or a custom server emitting the wrong object kind for a field.
Common situations: Client/server version mismatch where a field's expected type changed; unofficial server returning mismatched object kinds; a malformed response from a patched server.
Related errors
- ${path}: dispatcher with guid ${arg._guid} has type ${arg._t
- Object with guid ${arg.guid} was not bound in the connection
- ${path}: object with guid ${guid} has type ${dispatcher._typ
- ${path}: expected dispatcher ${names.toString()}
- ${path}: channels are not expected in SocksSupport
AI-assisted analysis of microsoft/playwright@c8fc3bf8d3 (2026-08-12).
Data as JSON: /api/errors/1bf9cd0da4cc1034.
Report an issue: GitHub.