jackwener/OpenCLI · error · CommandExecutionError

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

Error message

xiaohongshu creator-note-detail: signed API ${suffix} returned a non-text body

What it means

parseCapturedJson throws this CommandExecutionError when a captured signed API response has capture.ok === true but capture.body is not a string. The fetch/XHR hook always stores body as text (resp.clone().text() / responseText), so a non-string body means the capture object was never populated by the hook or was corrupted — the library cannot safely JSON.parse it.

Source

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

        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))};
    const shouldCapture = (url) => {
      try {
        return targetPaths.includes(new URL(String(url), window.location.origin).pathname);

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Close and reopen the browser tab (or restart the CLI run) so installXhsFetchCaptureHook resets window.__xhsCapture = {} and reinstalls a clean fetch/XHR hook.
  2. Disable browser extensions or automation overlays that may tamper with fetch/XHR responses on creator.xiaohongshu.com.
  3. Retry the command; a transient body-read failure inside the hook leaves ok:true with no body on the next poll only if re-requested — a fresh SPA navigation re-fires the signed requests.
  4. If it reproduces, verify the endpoint still returns a text body by opening the network tab and checking the datacenter/note response.

Example fix

// before
run('xiaohongshu creator-note-detail', { 'note-id': id }); // throws on corrupt capture
// after
try {
  return await run('xiaohongshu creator-note-detail', { 'note-id': id });
} catch (e) {
  if (/non-text body/.test(e.message)) {
    return await runWithFreshTab('xiaohongshu creator-note-detail', { 'note-id': id });
  }
  throw e;
}
Defensive patterns

Strategy: type-guard

Type guard

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

Try / catch

try {
  return await run('xiaohongshu creator-note-detail', { 'note-id': id });
} catch (e) {
  if (/non-text body/.test(e.message)) return await runInFreshTab('xiaohongshu creator-note-detail', { 'note-id': id });
  throw e;
}

Prevention

When it happens

Trigger: window.__xhsCapture[url] exists for the endpoint suffix but its body field is undefined or non-string — e.g. the clone().text() promise rejected before body was set, an interception/response rewrite stripped the body, or an object at that URL key was written by something other than the capture hook.

Common situations: Another browser extension or injected script overwrote window.__xhsCapture; the response body was consumed/blocked before cloning (streams, service workers); running against a page version where the hook's text() silently fails; reusing a stale tab whose hook state is inconsistent.

Related errors


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