jackwener/OpenCLI · error · CommandExecutionError

Gmail ${operation} requires native browser keyboard input

Error message

Gmail ${operation} requires native browser keyboard input

What it means

After typing, submitSearch must press Enter natively; if the page exposes neither cdp (for Input.dispatchKeyEvent) nor nativeKeyPress, it throws this CommandExecutionError. A synthetic DOM Enter event would not reliably trigger Gmail's search, so the library requires a real keyboard path and fails otherwise.

Source

Thrown at clis/gmail/utils.js:475

    field.focus();
    field.select();
    return true;
  }`), `${operation} search preparation`);
  if (prepared !== true) throw new CommandExecutionError(`Gmail ${operation} could not find the search input`);
  if (typeof page.nativeType !== 'function') {
    throw new CommandExecutionError(`Gmail ${operation} requires native browser input`);
  }
  await page.nativeType(query);
  const actual = unwrapBrowserResult(await page.evaluate(`() => document.querySelector('input[name="q"]')?.value || ''`), `${operation} search input verification`);
  if (actual !== query) throw new CommandExecutionError(`Gmail ${operation} could not set the search query exactly`);
  if (typeof page.cdp === 'function') {
    const key = { key: 'Enter', code: 'Enter', windowsVirtualKeyCode: 13, nativeVirtualKeyCode: 13 };
    await page.cdp('Input.dispatchKeyEvent', { type: 'rawKeyDown', ...key });
    await page.cdp('Input.dispatchKeyEvent', { type: 'keyUp', ...key });
  } else if (typeof page.nativeKeyPress === 'function') {
    await page.nativeKeyPress('Enter');
  } else {
    throw new CommandExecutionError(`Gmail ${operation} requires native browser keyboard input`);
  }
}

export async function queryThreads(page, query, { account = 0, limit = DEFAULT_LIMIT } = {}) {
  const normalizedQuery = cleanString(query);
  if (!normalizedQuery) throw new ArgumentError('Gmail search query cannot be empty');
  await ensureGmailReady(page, account, 'thread list');
  await installGmailCapture(page, account, 'bv', 'thread list');

  const rows = [];
  const seen = new Set();
  const pages = Math.ceil(limit / PAGE_SIZE);
  for (let pageNumber = 1; pageNumber <= pages; pageNumber += 1) {
    if (pageNumber === 1) {
      await submitSearch(page, normalizedQuery, 'thread list');
    } else {
      const target = unwrapBrowserResult(await page.evaluate(`() => {
        const labels = /(older|较旧|較舊|下一页|下一頁)/i;

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Use the library's standard page wrapper that provides cdp or nativeKeyPress
  2. Implement nativeKeyPress on your wrapper via the driver's keyboard API (e.g. page.keyboard.press('Enter'))
  3. Expose a CDP passthrough (page.cdp delegating to CDPSession.send) if using Puppeteer directly
  4. Check typeof page.cdp === 'function' || typeof page.nativeKeyPress === 'function' before running Gmail searches

Example fix

// before: wrapper lacks both dispatch paths
await queryThreads(page, 'in:unread');
// after: add a native key press to the wrapper
page.nativeKeyPress = (key) => page.keyboard.press(key);
await queryThreads(page, 'in:unread');
Defensive patterns

Strategy: validation

Validate before calling

if (typeof page?.cdp !== 'function' && typeof page?.nativeKeyPress !== 'function') {
  throw new Error('page wrapper must support cdp() or nativeKeyPress() for Gmail search');
}

Type guard

function supportsEnterKey(page) {
  return typeof page?.cdp === 'function' || typeof page?.nativeKeyPress === 'function';
}

Try / catch

try {
  await queryThreads(page, 'has:attachment');
} catch (e) {
  if (/requires native browser keyboard input/.test(e.message)) {
    console.error('Add nativeKeyPress or cdp passthrough to the page wrapper');
  } else throw e;
}

Prevention

When it happens

Trigger: queryThreads/listLabels reaches the Enter step with a page wrapper that has neither page.cdp nor page.nativeKeyPress — e.g. a minimal shim or a driver bridge missing keyboard dispatch.

Common situations: Custom page objects with evaluate/sleep but no keyboard/CDP passthrough; restricted environments where CDP is disabled; version mismatch where the driver exposes different key-dispatch names.

Related errors


AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29). Data as JSON: /api/errors/67be6815e36812d0. Report an issue: GitHub.