jackwener/OpenCLI · error · CommandExecutionError

weixin search returned an unreadable browser payload

Error message

weixin search returned an unreadable browser payload

What it means

Thrown when the browser-side extraction returns something other than an object with a `rows` array — i.e. the evaluate script produced null, a non-object, or an object missing the expected rows field. The library treats this as a page-structure change it cannot safely interpret, rather than returning garbage. It is a data-integrity guard, not a user-input error.

Solutions

  1. Upgrade the CLI to the latest version so extraction selectors match the current Sogou page
  2. Open weixin.sogou.com manually and inspect whether the result-page structure changed
  3. Retry later if Sogou is A/B testing — the structure may revert
  4. Report the payload shape change to the CLI maintainers if it persists
Defensive patterns

Strategy: try-catch

Type guard

function isSearchPayload(p) {
  return p !== null && typeof p === 'object' && Array.isArray(p.rows);
}

Try / catch

try { rows = await weixinSearch(q); }
catch (e) { if (String(e.message).includes('unreadable browser payload')) return fallbackToNewerCliVersion(); throw e; }

Prevention

When it happens

Trigger: Sogou's HTML/JS changed so the extraction script returns null or an unexpected shape; the page rendered an error/interstitial whose DOM the script mishandles; the evaluate script itself threw and the payload variable never got the expected shape.

Common situations: Sogou ships a frontend redesign or A/B test variant; anti-bot serving a different page template; stale CLI version whose embedded extraction script no longer matches the live page.

Related errors


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

Appendix: source

Thrown at clis/weixin/search.js:123

        }

        const pageNo = normalizePage(kwargs.page);
        const limit = normalizeLimit(kwargs.limit);
        const searchUrl = buildSearchUrl(query, pageNo);

        let payload;
        try {
            await page.goto(searchUrl);
            await page.wait(2);
            payload = await page.evaluate(buildExtractSearchResultsEvaluate());
        }
        catch (error) {
            const detail = error instanceof Error ? error.message : String(error);
            throw new CommandExecutionError('weixin search failed while loading Sogou results', detail);
        }

        if (!payload || typeof payload !== 'object' || !Array.isArray(payload.rows)) {
            throw new CommandExecutionError('weixin search returned an unreadable browser payload', 'Sogou Weixin may have changed its result page structure.');
        }
        if (payload.blocked) {
            throw new CommandExecutionError('Sogou Weixin blocked this search request', 'Open weixin.sogou.com in Chrome and complete any verification before retrying.');
        }
        if (payload.invalidCount > 0) {
            throw new CommandExecutionError('Sogou Weixin returned article cards without required title or URL', 'The result page structure may have changed; refusing to return a partial result set.');
        }

        const rows = payload.rows;
        if (rows.length === 0 && payload.empty) {
            throw new EmptyResultError('weixin search', 'Try a different keyword or a different page number.');
        }
        if (rows.length === 0) {
            throw new CommandExecutionError('weixin search did not expose article result cards', 'Sogou Weixin may have changed its selectors or returned a transient shell page.');
        }

        return rows.slice(0, limit).map((row, index) => ({
            rank: (pageNo - 1) * 10 + index + 1,

View on GitHub (pinned to 49907e53dc)