jackwener/OpenCLI · error · CommandExecutionError

Xiaohongshu search failed: ${err?.message ?? String(err)}

Error message

Xiaohongshu search failed: ${err?.message ?? String(err)}

What it means

A catch-all wrapper at the end of the xiaohongshu search command: any unexpected error that is not already a CliError is rethrown as a CommandExecutionError prefixed with 'Xiaohongshu search failed:'. It preserves the original message but loses the original stack/type, so you must read the embedded message to diagnose.

Source

Thrown at clis/xiaohongshu/search.js:917

                }
            }
            const rows = harvest.rows
                .filter((item) => item.title)
                .slice(0, limit);
            if (rows.length === 0) {
                throw new EmptyResultError('xiaohongshu search', 'No usable notes were rendered for this query.');
            }
            return rows
                .map((item, i) => ({
                rank: i + 1,
                ...item,
                published_at: noteIdToDate(item.url),
            }));
        }
        catch (err) {
            if (err instanceof CliError)
                throw err;
            throw new CommandExecutionError(`Xiaohongshu search failed: ${err?.message ?? String(err)}`);
        }
    },
});
export const __test__ = {
    harvestOptionsForLimit,
    stripXhsAuthorDateSuffix,
};

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Read the embedded message after the prefix — it is the original error's message — and fix that root cause.
  2. Verify network connectivity and that the search URL loads in the logged-in browser.
  3. Increase navigation/operation timeouts if the embedded message indicates a timeout.
  4. Catch this in your caller and retry with backoff for transient navigation failures.
  5. If the embedded message is an opaque TypeError, update the library — it may be a selector/contract change on the site.

Example fix

// before
const rows = await xhsSearch(query);
// after
try {
  const rows = await xhsSearch(query);
} catch (err) {
  const cause = String(err.message).replace('Xiaohongshu search failed: ', '');
  if (/timeout|net::/i.test(cause)) return await retryWithBackoff(() => xhsSearch(query));
  throw err;
}
Defensive patterns

Strategy: try-catch

Validate before calling

if (!browser.isConnected()) throw new Error('browser must be connected before running xiaohongshu search');

Type guard

function isCliError(e) { return e instanceof CliError; }

Try / catch

try {
  return await xhsSearch(query);
} catch (err) {
  if (isCliError(err)) throw err;
  const cause = err.message.replace(/^Xiaohongshu search failed: /, '');
  if (/timeout|net::ERR/i.test(cause)) return retryWithBackoff(() => xhsSearch(query));
  throw err;
}

Prevention

When it happens

Trigger: Any non-CliError exception escapes the try block in the command handler — e.g. navigation failures from page.goto, evaluate timeouts inside collectSearchHarvest, noteIdToDate input errors, or other runtime errors during harvest/processing.

Common situations: Navigation timeout because the search page never loaded; browser disconnected mid-harvest; page.evaluate returning undefined and downstream code throwing a TypeError; network outage during the search.

Related errors


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