jackwener/OpenCLI · error · CommandExecutionError

BOSS search requires CDP network capture

Error message

BOSS search requires CDP network capture

What it means

captureJobList requires the page object to expose CDP network capture (startNetworkCapture/readNetworkCapture) so it can intercept BOSS's job-list JSON response instead of scraping HTML. If those methods are missing or startNetworkCapture('joblist.json') fails, it throws this CommandExecutionError.

Solutions

  1. Pass the library's wrapped browser page object (the one with startNetworkCapture/readNetworkCapture) to the command
  2. Re-launch the browser session — a crashed or closed target makes startNetworkCapture return false
  3. Ensure no other CDP client/debugger is already attached to the page
  4. Upgrade @jackwener/opencli to a version where the page wrapper provides CDP capture
  5. Verify the page is a live browser page (requirePage passes) and not a mock/test double

Example fix

// before
const page = await puppeteer.launch().newPage();
await cli('boss', 'search', { query: 'node' }); // page passed internally lacks capture
// after: use the library's browser/page wrapper
const page = await opencli.browser.getPage();
await cli('boss', 'search', { query: 'node' });
Defensive patterns

Strategy: type-guard

Validate before calling

const supportsCapture = typeof page.startNetworkCapture === 'function' &&
  typeof page.readNetworkCapture === 'function';
if (!supportsCapture) throw new Error('need a CDP-capable page from the library wrapper');

Type guard

function isCdpPage(page) {
  return Boolean(page) && typeof page.startNetworkCapture === 'function' &&
    typeof page.readNetworkCapture === 'function';
}

Try / catch

try {
  return await cli('boss', 'search', opts);
} catch (e) {
  if (String(e.message).includes('CDP network capture')) {
    await reopenBrowserSession(); // relaunch page
    return cli('boss', 'search', opts);
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling boss search with a page object that is not a CDP-capable browser page (mock, plain Puppeteer page without the extension API, or a session where starting the capture failed e.g. target already closed or another capture is active).

Common situations: Passing a bare puppeteer.Page instead of the library's wrapped page; running in an environment without DevTools protocol access (already-attached debugger, restricted webview); stale/crashed browser target; using an older library version whose page wrapper lacks capture support.

Related errors


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

Appendix: source

Thrown at clis/boss/search.js:98

        return '';
    if (JOB_TYPE_MAP[input] !== undefined)
        return JOB_TYPE_MAP[input];
    if (JOB_TYPE_CODES.has(input))
        return input;
    throw new ArgumentError(`Invalid jobType: ${input}`, 'Use one of: 全职, 兼职, 实习, 不限');
}
function formatBossOnline(value) {
    if (value === true)
        return 'Y';
    if (value === false)
        return 'N';
    return '';
}
async function captureJobList(page, url) {
    if (typeof page.startNetworkCapture !== 'function' ||
        typeof page.readNetworkCapture !== 'function' ||
        !await page.startNetworkCapture('joblist.json')) {
        throw new CommandExecutionError('BOSS search requires CDP network capture');
    }
    await page.readNetworkCapture();
    for (let attempt = 0; attempt < 2; attempt++) {
        const separator = url.includes('?') ? '&' : '?';
        await navigateTo(page, `${url}${separator}_opencli=${Date.now()}`, 5);
        await page.wait(1);
        const captures = await page.readNetworkCapture();
        for (const entry of Array.isArray(captures) ? captures : []) {
            if (!String(entry?.url || '').includes('joblist.json') ||
                Number(entry?.responseStatus || 0) !== 200 ||
                typeof entry?.responsePreview !== 'string') {
                continue;
            }
            let payload;
            try {
                payload = JSON.parse(entry.responsePreview);
            } catch {
                continue;

View on GitHub (pinned to 49907e53dc)