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
A CliError with code SECURITY_BLOCK thrown when the in-page extraction script (buildDownloadExtractJs) reports `securityBlock: true`, meaning Xiaohongshu risk control intercepted the note detail page (captcha, login wall, or block page) instead of returning note content. The library detects this marker and refuses to continue so it does not scrape a block page. The remediation hint depends on whether the input was a full URL or a bare note ID.
Source
Thrown at clis/xiaohongshu/download.js:226
access: 'read',
description: '下载小红书笔记中的图片和视频',
domain: 'www.xiaohongshu.com',
strategy: Strategy.COOKIE,
navigateBefore: false,
args: [
{ name: 'note-id', positional: true, required: true, help: 'Full Xiaohongshu note URL with xsec_token, or xhslink short link' },
{ name: 'output', default: './xiaohongshu-downloads', help: 'Output directory' },
],
columns: ['index', 'type', 'status', 'size'],
func: async (page, kwargs) => {
const rawInput = String(kwargs['note-id']);
const output = kwargs.output;
const noteId = parseNoteId(rawInput);
await page.goto(buildNoteUrl(rawInput, { allowShortLink: true, commandName: 'xiaohongshu download' }));
await page.wait({ time: 1 + Math.random() * 2 });
const data = await page.evaluate(buildDownloadExtractJs(noteId));
if (data?.securityBlock) {
throw new CliError('SECURITY_BLOCK', 'Xiaohongshu security block: the note detail page was blocked by risk control.', /^https?:\/\//.test(rawInput)
? '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 || typeof data !== 'object' || !Array.isArray(data.media)) {
throw new CommandExecutionError('Xiaohongshu media extraction returned malformed payload.');
}
if (data.media.length === 0) {
throw new EmptyResultError('xiaohongshu download', 'No downloadable media found on this note.');
}
// Extract cookies for authenticated downloads
const cookies = formatCookieHeader(await page.getCookies({ domain: 'xiaohongshu.com' }));
const resolvedNoteId = typeof data.noteId === 'string' && data.noteId.trim()
? data.noteId.trim()
: noteId;
return downloadMedia(data.media, {
output,
subdir: resolvedNoteId,
cookies,View on GitHub (pinned to 49907e53dc)
Solutions
- Use the full note URL from search results including a fresh xsec_token instead of a bare note ID.
- Wait and retry later, or switch to a different session/account/IP.
- Slow down request rate between downloads (the code already waits 1-2s randomly; increase it).
- Log in again / refresh cookies if the session was invalidated.
Example fix
// before
await cli.run('xiaohongshu download', { input: '65f1abc123' });
// after
await cli.run('xiaohongshu download', { input: 'https://www.xiaohongshu.com/explore/65f1abc123?xsec_token=ABFreshToken' }); Defensive patterns
Strategy: try-catch
Validate before calling
// Prefer full URLs with xsec_token; detect bare IDs upfront
function needsXsecToken(input) {
return !/^https?:\/\//.test(input) || !input.includes('xsec_token=');
}
if (needsXsecToken(input)) console.warn('bare note id / missing xsec_token — high security-block risk'); Type guard
function isSecurityBlock(err) { return err instanceof Error && err.code === 'SECURITY_BLOCK'; } Try / catch
try {
await cli.run('xiaohongshu download', { input: url });
} catch (err) {
if (err.code === 'SECURITY_BLOCK') {
await sleep(backoffMs); // rotate session/IP or wait, then retry
return downloadNote(url);
}
throw err;
} Prevention
- Always use full note URLs taken from search results, including a fresh xsec_token.
- Throttle requests well below the built-in 1-2s wait; add jitter and longer delays for batch jobs.
- Rotate sessions/accounts/IPs when downloading many notes.
- Re-fetch URLs periodically — xsec_tokens expire.
When it happens
Trigger: Running `xiaohongshu download` with input that leads to a risk-controlled note detail page: a bare note ID without xsec_token, an expired/invalid xsec_token, too-frequent requests from one session/IP, or navigating to buildNoteUrl when the account is flagged.
Common situations: Scraping many notes in quick succession from the same session; using a bare note ID copied from elsewhere (missing the xsec_token query param); reusing an old share URL whose token expired; running from a datacenter IP that Xiaohongshu blocks.
Related errors
- SECURITY_BLOCK
- Boss rejected the current browser environment: ${data.messag
- Xianyu blocked by verification / risk control
- Xianyu item detail is blocked by verification or risk contro
- SECURITY_BLOCK
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/ba944282db573a10.
Report an issue: GitHub.