jackwener/OpenCLI · error · CommandExecutionError

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

Error message

xiaohongshu creator-note-detail: signed API ${suffix} returned malformed ${key}

What it means

assertOptionalArray guards optional fields in a captured signed-API payload: if a key is present it must be an array. When the creator-platform endpoint returns a field like hour/day/stats that exists but is not an array (object, string, null-shaped), the command rejects the payload as malformed.

Source

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

    if (!url)
        return null;
    try {
        const parsed = new URL(String(url), 'https://creator.xiaohongshu.com');
        return DETAIL_API_ENDPOINTS.find((endpoint) => parsed.pathname === endpoint.suffix) ?? null;
    }
    catch {
        return null;
    }
}
function findCapturedUrl(captureMap, suffix) {
    return Object.keys(captureMap).find((url) => detailApiEndpointForUrl(url)?.suffix === suffix);
}
function isPlainObject(value) {
    return value !== null && typeof value === 'object' && !Array.isArray(value);
}
function assertOptionalArray(payload, key, suffix) {
    if (key in payload && !Array.isArray(payload[key])) {
        throw new CommandExecutionError(`xiaohongshu creator-note-detail: signed API ${suffix} returned malformed ${key}`);
    }
}
function assertOptionalPlainObject(payload, key, suffix) {
    if (key in payload && !isPlainObject(payload[key])) {
        throw new CommandExecutionError(`xiaohongshu creator-note-detail: signed API ${suffix} returned malformed ${key}`);
    }
}
function validateCapturedPayload(payload, endpoint) {
    const suffix = endpoint.suffix;
    if (!isPlainObject(payload)) {
        throw new CommandExecutionError(`xiaohongshu creator-note-detail: signed API ${suffix} returned a malformed payload`);
    }
    if (endpoint.key === 'noteBase') {
        assertOptionalPlainObject(payload, 'hour', suffix);
        assertOptionalPlainObject(payload, 'day', suffix);
    }
    if (endpoint.key === 'audienceSource') {
        assertOptionalArray(payload, 'source', suffix);

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Dump the raw capture.body for the failing suffix and compare the field's actual shape against the expected array
  2. Handle the alternative shape (e.g. convert object-of-days to an array) before validation
  3. Update validateCapturedPayload/assertOptionalArray to accept the new API shape
  4. Check API/account permissions — a degraded response may accompany permission or plan changes

Example fix

// before
if (key in payload && !Array.isArray(payload[key])) {
    throw new CommandExecutionError(`... returned malformed ${key}`);
}
// after
if (key in payload && !Array.isArray(payload[key])) {
    const v = payload[key];
    if (v && typeof v === 'object' && !Array.isArray(v)) {
        payload[key] = Object.values(v); // coerce object-of-values to array
    } else {
        throw new CommandExecutionError(`... returned malformed ${key}`);
    }
}
Defensive patterns

Strategy: type-guard

Validate before calling

const isArr = (payload, key) => !(key in payload) || Array.isArray(payload[key]);
if (!isArr(payload, 'hour') || !isArr(payload, 'day')) throw new Error('unexpected stats shape');

Type guard

const isOptionalArray = (obj, key) => !(key in obj) || Array.isArray(obj[key]);

Try / catch

try {
  const detail = await cli.creatorNoteDetail(noteId);
} catch (err) {
  if (err.message.includes('returned malformed')) {
    // log raw capture.body and degrade gracefully (skip stats)
  } else throw err;
}

Prevention

When it happens

Trigger: validateCapturedPayload calls assertOptionalArray for a key (e.g. on audienceSource or noteBase-derived endpoints) and payload[key] is present but Array.isArray fails — typically an error object or nested object returned instead of a list.

Common situations: Xiaohongshu creator API changed the field shape (object keyed by date instead of array); API returned an error body that still parsed as JSON; account lacks analytics permission so the endpoint returns a different structure.

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.

Related errors


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