{"record":{"id":"d67f4f6d5118766b","repo":"jackwener/OpenCLI","slug":"xiaohongshu-creator-notes-captured-items-length","errorCode":null,"errorMessage":"xiaohongshu creator-notes: captured ${items.length} of ${Math.min(total, limit)} expected analyze rows; refusing partial results","messagePattern":"xiaohongshu creator-notes: captured (.+?) of (.+?) expected analyze rows; refusing partial results","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/xiaohongshu/creator-notes.js","lineNumber":323,"sourceCode":"        if (!clicked) break;\n        const before = items.length;\n        let advanced = false;\n        for (let attempt = 0; attempt < CAPTURE_POLL_ATTEMPTS; attempt++) {\n            await page.wait(CAPTURE_POLL_INTERVAL_S);\n            const raw = await page.evaluate('JSON.stringify(window.__xhsCapture || {})');\n            captureMap = parseCaptureMapPayload(raw);\n            const harvested = harvestAnalyzeListCaptures(captureMap);\n            if (harvested.items.length > before) {\n                items = harvested.items;\n                total = Math.max(total, harvested.total);\n                advanced = true;\n                break;\n            }\n        }\n        if (!advanced) break;\n    }\n    if (!isAnalyzeCaptureComplete(items, total, limit)) {\n        throw new CommandExecutionError(`xiaohongshu creator-notes: captured ${items.length} of ${Math.min(total, limit)} expected analyze rows; refusing partial results`);\n    }\n    const notes = mapAnalyzeItems(items).slice(0, limit);\n    const missingTitles = notes.filter((note) => !note.title).length;\n    if (missingTitles > 0) {\n        const titleMap = await fetchNoteManagerTitleMap(page, notes.length);\n        for (const note of notes) {\n            if (!note.title && note.id && titleMap.has(note.id)) {\n                note.title = titleMap.get(note.id);\n            }\n        }\n    }\n    return notes;\n}\nasync function fetchCreatorNotesByApi(page, limit) {\n    const pageSize = Math.min(Math.max(limit, 10), 20);\n    const maxPages = Math.max(1, Math.ceil(limit / pageSize));\n    const notes = [];\n    await page.goto(`https://creator.xiaohongshu.com/statistics/data-analysis?type=0&page_size=${pageSize}&page_num=1`);","sourceCodeStart":305,"sourceCodeEnd":341,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/xiaohongshu/creator-notes.js#L305-L341","documentation":"fetchCreatorNotesByCapture throws this CommandExecutionError when isAnalyzeCaptureComplete reports fewer analyze rows captured than expected (min(total, limit)). It deliberately refuses partial results rather than returning an incomplete table, because a silently truncated note list would be misleading.","triggerScenarios":"The paginated analyze endpoint returned fewer items than total before the loop exhausted its advance attempts — e.g. risk control throttled later pages, the SPA stopped firing requests mid-pagination, or the dashboard reduced page size so the completion predicate never saw all rows.","commonSituations":"Large limits (e.g. limit 100 with few captured pages) hitting rate limiting; session degraded mid-run so later signed calls return empty; Xiaohongshu changed analyze pagination shape; slow dashboard where the poll/advance budget ran out before all pages loaded.","solutions":["Lower the limit (e.g. 20 instead of 100) and paginate across multiple runs to avoid mid-run throttling.","Re-run the command; transient risk-control or load issues often complete on retry.","Confirm you stay logged in for the whole run and no redirect interrupted pagination.","Add waits/retries in your wrapper between runs to reduce risk-control pressure.","Update the CLI if Xiaohongshu changed the analyze endpoint's pagination or total semantics."],"exampleFix":"// before\nconst notes = await run('xiaohongshu creator-notes', { limit: 100 });\n// after\ntry {\n  return await run('xiaohongshu creator-notes', { limit: 100 });\n} catch (e) {\n  if (/refusing partial results/.test(e.message)) {\n    await sleep(5000);\n    return await run('xiaohongshu creator-notes', { limit: 20 }); // smaller batch\n  }\n  throw e;\n}","handlingStrategy":"retry","validationCode":"const limit = Number(kwargs.limit ?? 20);\nif (limit > 100) throw new Error('large limits risk partial captures; paginate instead');","typeGuard":null,"tryCatchPattern":"async function fetchAllNotes(totalWanted) {\n  const out = [];\n  for (let offset = 0; offset < totalWanted; offset += 20) {\n    out.push(...await withRetry(() => run('xiaohongshu creator-notes', { limit: 20 })));\n    await sleep(1500 + Math.random() * 1500);\n  }\n  return out.slice(0, totalWanted);\n}","preventionTips":["Keep per-run limits modest and paginate across runs.","Add jittered delays between runs to reduce risk-control throttling.","Retry once on 'refusing partial results' before surfacing failure.","Ensure the session stays valid for the entire pagination (no mid-run logouts).","Update the CLI if Xiaohongshu changes analyze pagination semantics."],"tags":["pagination","rate-limiting","xiaohongshu","partial-data"],"backgroundTag":"incomplete-paginated-capture","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}