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
- Close and reopen the browser tab (or restart the CLI run) so installXhsFetchCaptureHook resets window.__xhsCapture = {} and reinstalls a clean fetch/XHR hook.
- Disable browser extensions or automation overlays that may tamper with fetch/XHR responses on creator.xiaohongshu.com.
- 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.
- 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
- Run the command in a clean tab without interfering extensions.
- Never assign to window.__xhsCapture manually in your own evaluate scripts.
- Reset the tab between runs so the hook reinitializes the buffer.
- Retry once on this error — it is usually a one-off hook/read glitch.
- Check service workers on the domain that may intercept response bodies.
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
- xiaohongshu creator-note-detail: malformed signed datacenter
- xiaohongshu creator-note-detail: failed to read signed datac
- No feed items in the hydrated store.
- xiaohongshu/follow: malformed ${context} payload
- Browser session required for xiaohongshu follow
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/0ea7cc118a0b4545.
Report an issue: GitHub.