{"record":{"id":"bda0a0132863d491","repo":"jackwener/OpenCLI","slug":"xiaohongshu-creator-note-detail-failed-to-read-si","errorCode":null,"errorMessage":"xiaohongshu creator-note-detail: failed to read signed datacenter/note capture buffer","messagePattern":"xiaohongshu creator-note-detail: failed to read signed datacenter/note capture buffer","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/xiaohongshu/creator-note-detail.js","lineNumber":397,"sourceCode":"    // SPA-navigate inside the dashboard so the React router re-fires the\n    // signed datacenter/note/* requests under our hook. A second page.goto\n    // would wipe the hook before the first auto-fetch can land.\n    await page.evaluate(`(() => {\n    const target = '/statistics/note-detail?noteId=' + ${JSON.stringify(noteId)};\n    history.pushState({}, '', target);\n    window.dispatchEvent(new PopStateEvent('popstate'));\n  })()`);\n    const wantedSuffixes = DETAIL_API_ENDPOINTS.map((endpoint) => endpoint.suffix);\n    let captureMap = {};\n    for (let i = 0; i < CAPTURE_POLL_ATTEMPTS; i++) {\n        await page.wait(CAPTURE_POLL_INTERVAL_S);\n        let raw;\n        try {\n            raw = await page.evaluate('JSON.stringify(window.__xhsCapture || {})');\n            captureMap = typeof raw === 'string' ? JSON.parse(raw) : {};\n        }\n        catch {\n            throw new CommandExecutionError('xiaohongshu creator-note-detail: failed to read signed datacenter/note capture buffer');\n        }\n        if (!captureMap || typeof captureMap !== 'object' || Array.isArray(captureMap)) {\n            throw new CommandExecutionError('xiaohongshu creator-note-detail: malformed signed datacenter/note capture buffer');\n        }\n        const captured = wantedSuffixes.filter((suffix) => findCapturedUrl(captureMap, suffix));\n        if (captured.length === wantedSuffixes.length)\n            break;\n    }\n    const payload = {};\n    for (const endpoint of DETAIL_API_ENDPOINTS) {\n        const matchUrl = findCapturedUrl(captureMap, endpoint.suffix);\n        if (!matchUrl)\n            continue;\n        payload[endpoint.key] = parseCapturedJson(captureMap[matchUrl], endpoint);\n    }\n    return Object.keys(payload).length > 0 ? payload : null;\n}\nasync function captureNoteDetailDomData(page) {","sourceCodeStart":379,"sourceCodeEnd":415,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/xiaohongshu/creator-note-detail.js#L379-L415","documentation":"captureNoteDetailPayload throws this CommandExecutionError when page.evaluate('JSON.stringify(window.__xhsCapture || {})') itself rejects (or JSON.parse of the returned string fails). This means the CLI could not even read the capture buffer from the page — the execution context is gone or the page is not scriptable, distinct from the buffer merely being malformed.","triggerScenarios":"The page navigated/reloaded between hook installation and polling, destroying the JS context (execution context destroyed); the tab crashed or was closed; page.evaluate was rejected because the SPA hard-navigated instead of using history.pushState; the browser connection dropped.","commonSituations":"Xiaohongshu served a full-page redirect (e.g. to login or verification) that wiped the context mid-poll; long poll loop outlived a navigation; Chrome under automation ran out of memory and the renderer crashed; network hiccup dropped the DevTools connection.","solutions":["Re-run the command with a fresh tab so the hook is installed after any initial redirects complete.","Pre-login to creator.xiaohongshu.com first, so no mid-run redirect to the login page destroys the context.","Retry — transient renderer/DevTools failures often succeed on a second run.","Slow down or increase CAPTURE_POLL tolerance in your wrapper if large pages keep navigating during polling.","Check Chrome/automation health (tab count, memory) if it reproduces consistently."],"exampleFix":"// before\nconst rows = await run('xiaohongshu creator-note-detail', { 'note-id': id });\n// after\ntry {\n  const rows = await run('xiaohongshu creator-note-detail', { 'note-id': id });\n} catch (e) {\n  if (/failed to read signed .* capture buffer/.test(e.message)) {\n    await newTabAt('https://creator.xiaohongshu.com/new/home');\n    return await run('xiaohongshu creator-note-detail', { 'note-id': id });\n  }\n  throw e;\n}","handlingStrategy":"retry","validationCode":"// ensure the tab is alive and on the creator domain before invoking\nif (!tab.url.startsWith('https://creator.xiaohongshu.com')) await tab.goto('https://creator.xiaohongshu.com/new/home');","typeGuard":"function isPlainCaptureMap(v) {\n  return typeof v === 'object' && v !== null && !Array.isArray(v);\n}","tryCatchPattern":"async function withRetry(fn, n = 2) {\n  for (let i = 0; ; i++) {\n    try { return await fn(); }\n    catch (e) {\n      if (i >= n || !/capture buffer/.test(e.message)) throw e;\n      await sleep(2000);\n    }\n  }\n}","preventionTips":["Complete login first so no mid-run redirect destroys the page context.","Avoid navigating or reloading the tab while the command polls for captures.","Retry once automatically — context loss is often transient.","Keep Chrome/tab memory pressure low during automation runs.","Use a dedicated tab for CLI runs instead of a shared one."],"tags":["browser-automation","execution-context","xiaohongshu","page-navigation"],"backgroundTag":"execution-context-destroyed","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}