{"record":{"id":"414b4147d70f2231","repo":"jackwener/OpenCLI","slug":"xiaohongshu-creator-note-detail-signed-api-suff-414b41","errorCode":null,"errorMessage":"xiaohongshu creator-note-detail: signed API ${suffix} returned HTTP ${capture.status ?? 'non-2xx'}","messagePattern":"xiaohongshu creator-note-detail: signed API (.+?) returned HTTP (.+?)","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/xiaohongshu/creator-note-detail.js","lineNumber":306,"sourceCode":"        assertOptionalPlainObject(payload, 'day', suffix);\n    }\n    if (endpoint.key === 'audienceSource') {\n        assertOptionalArray(payload, 'source', suffix);\n    }\n    if (endpoint.key === 'audienceSourceDetail') {\n        for (const key of ['gender', 'age', 'city', 'interest']) {\n            assertOptionalArray(payload, key, suffix);\n        }\n    }\n    return payload;\n}\nfunction parseCapturedJson(capture, endpoint) {\n    const suffix = endpoint.suffix;\n    if (!capture || typeof capture !== 'object') {\n        throw new CommandExecutionError(`xiaohongshu creator-note-detail: malformed capture for ${suffix}`);\n    }\n    if (capture.ok !== true) {\n        throw new CommandExecutionError(`xiaohongshu creator-note-detail: signed API ${suffix} returned HTTP ${capture.status ?? 'non-2xx'}`);\n    }\n    if (typeof capture.body !== 'string') {\n        throw new CommandExecutionError(`xiaohongshu creator-note-detail: signed API ${suffix} returned a non-text body`);\n    }\n    try {\n        const envelope = JSON.parse(capture.body);\n        const payload = isPlainObject(envelope) && Object.hasOwn(envelope, 'data') ? envelope.data : envelope;\n        return validateCapturedPayload(payload, endpoint);\n    }\n    catch {\n        throw new CommandExecutionError(`xiaohongshu creator-note-detail: signed API ${suffix} returned invalid JSON or payload shape`);\n    }\n}\n// Capture the dashboard's signed datacenter/note responses on window.__xhsCapture\n// since a direct fetch() from page.evaluate bypasses the x-s signing and gets 406.\nasync function installXhsFetchCaptureHook(page) {\n    await page.evaluate(`(() => {\n    const targetPaths = ${JSON.stringify(DETAIL_API_ENDPOINTS.map((endpoint) => endpoint.suffix))};","sourceCodeStart":288,"sourceCodeEnd":324,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/xiaohongshu/creator-note-detail.js#L288-L324","documentation":"This CommandExecutionError is thrown by parseCapturedJson in clis/xiaohongshu/creator-note-detail.js when a captured signed datacenter/note API response reports capture.ok !== true, i.e. the dashboard's own fetch/XHR completed with a non-2xx HTTP status (or the status is unknown). The library wraps the browser's fetch/XHR to harvest responses the page itself makes, and refuses to hand back payloads from failed HTTP responses.","triggerScenarios":"A signed /datacenter/note/* endpoint called during the SPA navigation to /statistics/note-detail returns HTTP 401/403/404/406/5xx, so window.__xhsCapture[url] = { status, ok: false, body } is stored and parseCapturedJson rejects it. Note that a direct page-side fetch bypassing x-s signing gets 406, but here the page's own signed call failed.","commonSituations":"Expired or missing creator.xiaohongshu.com login cookies (401/403); wrong or deleted note_id (404); risk-control/anti-bot interception (406/461); transient 5xx from Xiaohongshu; the dashboard API surface changed and the suffix now maps to a different failing endpoint.","solutions":["Log into creator.xiaohongshu.com in the connected Chrome profile and refresh the session cookies, then retry.","Verify the note-id exists and belongs to the logged-in account (a wrong note_id yields 404).","Wait and retry — risk control (406-style blocks) is often transient; slow down polling/retries between runs.","Check the HTTP status embedded in the error to route: 401/403 → re-login, 404 → wrong note_id, 5xx → retry later.","Update the CLI if Xiaohongshu changed the datacenter API, so endpoint suffixes match current endpoints."],"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 (/HTTP 40[13]/.test(e.message)) await refreshCreatorLogin();\n  else if (/HTTP 404/.test(e.message)) throw new Error(`note ${id} not found`);\n  else throw e;\n}","handlingStrategy":"try-catch","validationCode":"const noteId = (id) => /^\\d+$/.test(String(id)) && isLoggedInToCreatorXhs();\nif (!noteId(args['note-id'])) throw new Error('need valid note-id and creator.xiaohongshu.com login');","typeGuard":"function isOkCapture(c) {\n  return typeof c === 'object' && c !== null && c.ok === true && typeof c.body === 'string';\n}","tryCatchPattern":"try {\n  const rows = await run('xiaohongshu creator-note-detail', { 'note-id': id });\n} catch (e) {\n  if (/returned HTTP (401|403)/.test(e.message)) await reloginCreatorXhs();\n  else if (/returned HTTP 404/.test(e.message)) throw new Error(`note ${id} not found`);\n  throw e;\n}","preventionTips":["Log in to creator.xiaohongshu.com and confirm the dashboard renders before running the command.","Validate note-id format and existence in your own code before invoking.","Keep sessions fresh; re-login when cookies age out.","Handle embedded HTTP status in the message to branch fixes (auth vs not-found vs 5xx).","Rate-limit your runs to avoid risk-control 406-style blocks."],"tags":["http-status","authentication","xiaohongshu","api-response"],"backgroundTag":"signed-api-non-2xx","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}