jackwener/OpenCLI · error · CommandExecutionError

xiaohongshu creator-note-detail: signed API ${suffix} return

Error message

xiaohongshu creator-note-detail: signed API ${suffix} returned HTTP ${capture.status ?? 'non-2xx'}

What it means

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.

Source

Thrown at clis/xiaohongshu/creator-note-detail.js:306

        assertOptionalPlainObject(payload, 'day', suffix);
    }
    if (endpoint.key === 'audienceSource') {
        assertOptionalArray(payload, 'source', suffix);
    }
    if (endpoint.key === 'audienceSourceDetail') {
        for (const key of ['gender', 'age', 'city', 'interest']) {
            assertOptionalArray(payload, key, suffix);
        }
    }
    return payload;
}
function parseCapturedJson(capture, endpoint) {
    const suffix = endpoint.suffix;
    if (!capture || typeof capture !== 'object') {
        throw new CommandExecutionError(`xiaohongshu creator-note-detail: malformed capture for ${suffix}`);
    }
    if (capture.ok !== true) {
        throw new CommandExecutionError(`xiaohongshu creator-note-detail: signed API ${suffix} returned HTTP ${capture.status ?? 'non-2xx'}`);
    }
    if (typeof capture.body !== 'string') {
        throw new CommandExecutionError(`xiaohongshu creator-note-detail: signed API ${suffix} returned a non-text body`);
    }
    try {
        const envelope = JSON.parse(capture.body);
        const payload = isPlainObject(envelope) && Object.hasOwn(envelope, 'data') ? envelope.data : envelope;
        return validateCapturedPayload(payload, endpoint);
    }
    catch {
        throw new CommandExecutionError(`xiaohongshu creator-note-detail: signed API ${suffix} returned invalid JSON or payload shape`);
    }
}
// Capture the dashboard's signed datacenter/note responses on window.__xhsCapture
// since a direct fetch() from page.evaluate bypasses the x-s signing and gets 406.
async function installXhsFetchCaptureHook(page) {
    await page.evaluate(`(() => {
    const targetPaths = ${JSON.stringify(DETAIL_API_ENDPOINTS.map((endpoint) => endpoint.suffix))};

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Log into creator.xiaohongshu.com in the connected Chrome profile and refresh the session cookies, then retry.
  2. Verify the note-id exists and belongs to the logged-in account (a wrong note_id yields 404).
  3. Wait and retry — risk control (406-style blocks) is often transient; slow down polling/retries between runs.
  4. Check the HTTP status embedded in the error to route: 401/403 → re-login, 404 → wrong note_id, 5xx → retry later.
  5. Update the CLI if Xiaohongshu changed the datacenter API, so endpoint suffixes match current endpoints.

Example fix

// before
const rows = await run('xiaohongshu creator-note-detail', { 'note-id': id });
// after
try {
  const rows = await run('xiaohongshu creator-note-detail', { 'note-id': id });
} catch (e) {
  if (/HTTP 40[13]/.test(e.message)) await refreshCreatorLogin();
  else if (/HTTP 404/.test(e.message)) throw new Error(`note ${id} not found`);
  else throw e;
}
Defensive patterns

Strategy: try-catch

Validate before calling

const noteId = (id) => /^\d+$/.test(String(id)) && isLoggedInToCreatorXhs();
if (!noteId(args['note-id'])) throw new Error('need valid note-id and creator.xiaohongshu.com login');

Type guard

function isOkCapture(c) {
  return typeof c === 'object' && c !== null && c.ok === true && typeof c.body === 'string';
}

Try / catch

try {
  const rows = await run('xiaohongshu creator-note-detail', { 'note-id': id });
} catch (e) {
  if (/returned HTTP (401|403)/.test(e.message)) await reloginCreatorXhs();
  else if (/returned HTTP 404/.test(e.message)) throw new Error(`note ${id} not found`);
  throw e;
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29). Data as JSON: /api/errors/414b4147d70f2231. Report an issue: GitHub.