microsoft/playwright · error · ValidationError
${path}: no object with guid ${guid}
Error message
${path}: no object with guid ${guid} What it means
ValidationError raised in DispatcherConnection._tChannelImplFromWire when an inbound message references a guid that is not present in _dispatcherByGuid. Every channel argument must resolve to a live server-side Dispatcher; a missing guid means the handle is unknown here — typically because the object was already disposed (context/page closed), was never created on this connection, or the guid was fabricated.
Source
Thrown at packages/playwright-core/src/server/dispatchers/dispatcher.ts:248
binary: this._isInProcess ? 'buffer' : 'toBase64',
isUnderTest,
};
}
private _validatorFromWireContext(): ValidatorContext {
return {
tChannelImpl: this._tChannelImplFromWire.bind(this),
binary: this._isInProcess ? 'buffer' : 'fromBase64',
isUnderTest,
};
}
private _tChannelImplFromWire(names: '*' | string[], arg: any, path: string, context: ValidatorContext): any {
if (arg && typeof arg === 'object' && typeof arg.guid === 'string') {
const guid = arg.guid;
const dispatcher = this._dispatcherByGuid.get(guid);
if (!dispatcher)
throw new ValidationError(`${path}: no object with guid ${guid}`);
if (names !== '*' && !names.includes(dispatcher._type))
throw new ValidationError(`${path}: object with guid ${guid} has type ${dispatcher._type}, expected ${names.toString()}`);
return dispatcher;
}
throw new ValidationError(`${path}: expected guid for ${names.toString()}`);
}
private _tChannelImplToWire(names: '*' | string[], arg: any, path: string, context: ValidatorContext): any {
if (arg instanceof Dispatcher) {
if (names !== '*' && !names.includes(arg._type))
throw new ValidationError(`${path}: dispatcher with guid ${arg._guid} has type ${arg._type}, expected ${names.toString()}`);
return { guid: arg._guid };
}
throw new ValidationError(`${path}: expected dispatcher ${names.toString()}`);
}
existingDispatcher<DispatcherType>(object: any): DispatcherType | undefined {
return this._dispatcherByObject.get(object) as DispatcherType | undefined;View on GitHub (pinned to c8fc3bf8d3)
Solutions
- Do not reuse handles after their owner is closed; close contexts/browser explicitly and drop references.
- Keep handles scoped to the connection that created them and never pass a guid across connections.
- After closing a context/browser, null out cached handles so accidental reuse fails locally rather than at the server.
- If you build protocol messages by hand, validate that every guid you send came from a prior result on the same connection.
Example fix
// before: reuse page after context close
const page = await context.newPage();
await context.close();
await page.click('#x'); // guid unknown -> ValidationError
// after: drop references on close
const page = await context.newPage();
await context.close();
// page is now invalid; do not call methods on it Defensive patterns
Strategy: validation
Validate before calling
// Track live handles per connection and check before reuse.
const live = new WeakSet<object>();
function track<T extends object>(h: T): T { live.add(h); return h; }
function isLive(h: object): boolean { return live.has(h); }
// after context/browser close, callers should stop using tracked handles Type guard
function isLiveHandle<T extends { _guid?: string }>(h: T | null | undefined, registry: Set<string>): h is T {
return !!h && typeof h._guid === 'string' && registry.has(h._guid);
} Try / catch
try {
await page.click('#x');
} catch (e) {
if (/no object with guid/.test(e.message)) { /* handle was disposed; recreate or end session */ }
else throw e;
} Prevention
- Never use a handle after its context/browser is closed; null references on close.
- Keep handles on the connection that created them; never pass guids across connections.
- Avoid caching handles across long awaits where close can intervene.
- When building protocol messages by hand, validate each guid against current live handles.
When it happens
Trigger: Sending any RPC that takes a channel handle (page, frame, elementHandle, request, response, JSHandle, etc.) whose guid is no longer registered: reusing a handle after its browser/context closed; sending a guid from a different connection; passing a guid string that was made up or truncated.
Common situations: Use-after-close: holding a Page/ElementHandle across an await during which the context is torn down, then calling a method on it; multi-connection code mixing handles from one connection into another; long-running scripts that cache handles past the object's lifetime.
Related errors
- ${path}: object with guid ${guid} has type ${dispatcher._typ
- ${path}: expected guid for ${names.toString()}
- ${path}: expected channel ${names.toString()}
- Cannot find object to "${method}": ${guid}
- Unknown new child: ${params.guid}
AI-assisted analysis of microsoft/playwright@c8fc3bf8d3 (2026-08-12).
Data as JSON: /api/errors/f5116d08a46c54e2.
Report an issue: GitHub.