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

  1. Do not reuse handles after their owner is closed; close contexts/browser explicitly and drop references.
  2. Keep handles scoped to the connection that created them and never pass a guid across connections.
  3. After closing a context/browser, null out cached handles so accidental reuse fails locally rather than at the server.
  4. 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

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


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