microsoft/playwright · error · ValidationError

: object with guid has type , expected

Error message

${path}: object with guid ${guid} has type ${dispatcher._type}, expected ${names.toString()}

What it means

ValidationError raised in _tChannelImplFromWire when the guid resolves to a Dispatcher but its _type is not in the accepted names list for that parameter. The wire validator expects a specific channel type (e.g. 'Page', 'Frame', 'ElementHandle'); receiving a different but existing handle type is rejected. The message names the actual type and the expected types to pinpoint the mismatch.

Solutions

  1. Send the exact handle type the method's channel signature declares (see channels.d.ts / protocol.yml).
  2. Add type checks on the client side before sending: assert(handle._type === 'Page') or use the typed client API which encodes the constraint.
  3. Double-check refactors that touch handle plumbing — the guid is fine but the type is wrong.

Example fix

// before: sending a Page where a Frame is required
await connection.send('frame', 'click', { frame: page });

// after: pass the correct type
await connection.send('frame', 'click', { frame: page.mainFrame() });
Defensive patterns

Strategy: type-guard

Validate before calling

// Validate handle type before sending.
function assertChannel(handle: { _type?: string }, expected: string[]) {
  if (!handle || !expected.includes(handle._type!))
    throw new Error(`Expected ${expected.join('|')}, got ${handle?._type}`);
}

Type guard

function isChannelOf<T extends { _type: string }>(h: any, types: readonly string[]): h is T {
  return !!h && typeof h._type === 'string' && types.includes(h._type);
}

Prevention

When it happens

Trigger: Passing a Page where a Frame is required, an ElementHandle where a JSHandle is required, a BrowserType where a Browser is required, etc. — i.e. a valid handle of the wrong channel type. Common with hand-rolled protocol clients or dynamic dispatch that picks the wrong handle variable.

Common situations: Custom protocol/transport code that confuses similar handle types (Page vs Frame, ElementHandle vs JSHandle, Request vs Response); refactors that change a field but leave the wrong handle being sent.

Related errors


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

Appendix: source

Thrown at packages/playwright-core/src/server/dispatchers/dispatcher.ts:252

    };
  }

  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 500c9c822c)