jackwener/OpenCLI · error · CliError
SECURITY_BLOCK
SECURITY_BLOCK
Error message
Xiaohongshu security block: the note detail page was blocked by risk control.
What it means
The comments extractor flags data.securityBlock when the note detail page was intercepted by Xiaohongshu's risk-control system instead of showing the note. The command surfaces this as a CliError with code SECURITY_BLOCK and a hint that differs depending on whether the caller passed a full URL or a bare note ID.
Source
Thrown at clis/xiaohongshu/comments.js:310
args: [
{ name: 'note-id', required: true, positional: true, help: 'Full Xiaohongshu note URL with xsec_token' },
{ name: 'limit', type: 'int', default: 20, help: 'Number of top-level comments (max 50)' },
{ name: 'with-replies', type: 'boolean', default: false, help: 'Include nested replies; reply_to is the direct target shown by the page' },
],
columns: ['rank', 'author', 'userId', 'profileUrl', 'text', 'likes', 'time', 'is_reply', 'reply_to', 'images'],
func: async (page, kwargs) => {
const limit = parseCommentLimit(kwargs.limit);
const withReplies = Boolean(kwargs['with-replies']);
const raw = String(kwargs['note-id']);
const noteId = parseNoteId(raw);
await page.goto(buildNoteUrl(raw, { commandName: 'xiaohongshu comments' }));
await page.wait({ time: 2 + Math.random() * 3 });
const data = await page.evaluate(buildCommentsExtractJs(withReplies, limit));
if (!data || typeof data !== 'object') {
throw new EmptyResultError('xiaohongshu/comments', 'Unexpected evaluate response');
}
if (data.securityBlock) {
throw new CliError('SECURITY_BLOCK', 'Xiaohongshu security block: the note detail page was blocked by risk control.', /^https?:\/\//.test(raw)
? 'The page may be temporarily restricted. Try again later or from a different session.'
: 'Try using a full URL from search results (with xsec_token) instead of a bare note ID.');
}
if (data.loginWall) {
throw new AuthRequiredError('www.xiaohongshu.com', 'Note comments require login');
}
// noteId currently unused after parsing — kept for symmetry with the note command
void noteId;
const all = normalizeCommentRows(data.results, 'xiaohongshu/comments');
// authorHrefRaw is a raw transport field from the extractor; it is consumed
// here into userId / profileUrl and intentionally not part of the row shape.
const enrich = (c, i) => ({
rank: i + 1,
author: c.author,
userId: c.authorHrefRaw ? parseXhsProfileHref(c.authorHrefRaw) : '',
profileUrl: c.authorHrefRaw ? buildXhsProfileUrl(c.authorHrefRaw) : '',
text: c.text,
likes: c.likes,View on GitHub (pinned to 49907e53dc)
Solutions
- If you passed a bare note ID, switch to the full note URL from search results including xsec_token
- Wait and retry later, or use a different session/IP (the error hint suggests both)
- Slow down request rate, add randomized waits, and reuse a warmed-up logged-in session
- Use a less suspicious browser profile (real user agent, headful mode, residential proxy)
Example fix
// before await cli comments '661a1b2c000000002203a1f5' --limit 20; // after await cli comments 'https://www.xiaohongshu.com/explore/661a1b2c000000002203a1f5?xsec_token=AB...' --limit 20;
Defensive patterns
Strategy: fallback
Try / catch
try {
const comments = await cli.comments(noteUrl);
} catch (err) {
if (err.code === 'SECURITY_BLOCK') {
// rotate session/IP, back off, or retry with full URL incl. xsec_token
} else throw err;
} Prevention
- Always pass full URLs from search results including xsec_token
- Throttle request rate and randomize waits between notes
- Use residential IPs and realistic browser fingerprints
- Reuse a warmed, logged-in session instead of fresh anonymous ones
When it happens
Trigger: page.evaluate returns { securityBlock: true } — the rendered page matched the extractor's risk-control/captcha detection (verify page, slider captcha, or an 'environment abnormal' interstitial).
Common situations: Scraping many notes from one session/IP triggers rate limiting; datacenter IP or headless browser fingerprint flagged; bare note ID without xsec_token is rejected by risk control more aggressively; stale session cookies.
Related errors
- SECURITY_BLOCK
- Sogou Weixin blocked this search request
- BOSS search page did not expose its job-list response
- Ctrip is asking for a captcha; complete it in your browser s
- hotels.ctrip.com
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/8812379ee259345e.
Report an issue: GitHub.