jackwener/OpenCLI · error · CommandExecutionError

gov-policy ${command} browser extraction failed: ${error?.me

Error message

gov-policy ${command} browser extraction failed: ${error?.message ?? error}

What it means

Thrown by wrapBrowserError as a catch-all: any error thrown during browser automation that is not already an ArgumentError, EmptyResultError, or CommandExecutionError is re-wrapped as `gov-policy <command> browser extraction failed: <message>`. This normalizes low-level failures (Puppeteer timeouts, target closed, navigation aborted) into the library's standard error type while preserving known errors untouched.

Source

Thrown at clis/gov-policy/utils.js:53

        context || 'The page structure may have changed or the page did not finish rendering.',
    );
}

export function requireRows(command, rows) {
    if (!Array.isArray(rows) || rows.length === 0) {
        throw new CommandExecutionError(
            `gov-policy ${command} extractor returned no result rows`,
            'The page structure may have changed or all result cards were missing required title fields.',
        );
    }
    return rows;
}

export function wrapBrowserError(command, error) {
    if (error instanceof ArgumentError || error instanceof EmptyResultError || error instanceof CommandExecutionError) {
        throw error;
    }
    throw new CommandExecutionError(`gov-policy ${command} browser extraction failed: ${error?.message ?? error}`);
}

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Read the inner message to identify the root cause (timeout vs crash vs navigation)
  2. Ensure a supported headless browser is installed and launchable (check Puppeteer deps in CI)
  3. Retry the command — transient navigation/timeouts often succeed on a second attempt
  4. Increase any available timeout options or run on a faster/stabler network connection

Example fix

// before
await runGovPolicy('search', { q: '网络安全' });
// after
try { await runGovPolicy('search', { q: '网络安全' }); }
catch (e) {
  if (/timeout|Target closed/i.test(e.message)) return retry(() => runGovPolicy('search', { q: '网络安全' }), 2);
  throw e;
}
Defensive patterns

Strategy: try-catch

Validate before calling

// Preflight browser launchability before running extraction
let browser;
try { browser = await puppeteer.launch({ headless: true }); await browser.close(); }
catch (e) { throw new Error('Headless browser unavailable: ' + e.message); }

Type guard

function isKnownCliError(e) { return e instanceof ArgumentError || e instanceof EmptyResultError || e instanceof CommandExecutionError; }

Try / catch

try {
  await runGovPolicy(command, args);
} catch (err) {
  if (/browser extraction failed/.test(err.message)) {
    const cause = err.message.replace(/.*failed: /, '');
    if (/timeout|Target closed|Navigation/i.test(cause)) return retryCommand(command, args);
    if (/browser|sandbox|libnss/i.test(cause)) console.error('Install Chromium deps: check puppeteer setup in this environment.');
    else throw err;
  } else throw err;
}

Prevention

When it happens

Trigger: Calling a gov-policy command when the underlying browser operation throws a foreign error: page.goto() timeout, browser crashed or target closed, navigation interrupted, PermissionError launching the headless browser, or a TypeError inside the injected script.

Common situations: Chromium not installed or blocked by sandboxing in CI containers, slow/blocked network causing navigation timeouts, the site closing connections, or memory pressure killing the browser tab.

Related errors


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