jackwener/OpenCLI · error · CommandExecutionError

xiaohongshu/unfollow: malformed ${context} payload

Error message

xiaohongshu/unfollow: malformed ${context} payload

What it means

Thrown by requireActionResult() in the xiaohongshu unfollow flow when a browser page.evaluate payload does not have the expected action-result shape. After unwrapEvaluateResult, the value must be a non-null, non-array object with a boolean `ok` field; otherwise the click/confirm step cannot tell success from failure and the command aborts with this malformed-payload error.

Source

Thrown at clis/xiaohongshu/unfollow.js:31

import { cli, Strategy } from '@jackwener/opencli/registry';
import { ArgumentError, AuthRequiredError, CliError, CommandExecutionError } from '@jackwener/opencli/errors';
import { normalizeXhsUserId } from './user-helpers.js';
import { unwrapEvaluateResult } from './shared.js';

const PROFILE_SETTLE_MS = 2500;
const MODAL_SETTLE_MS = 1500;
const STATE_FLIP_TIMEOUT_MS = 5000;
const USER_ID_RE = /^[a-zA-Z0-9]{8,32}$/;

function isXiaohongshuHost(hostname) {
    const host = String(hostname || '').toLowerCase();
    return host === 'xiaohongshu.com' || host.endsWith('.xiaohongshu.com');
}

function requireActionResult(payload, context) {
    const inner = unwrapEvaluateResult(payload);
    if (!inner || typeof inner !== 'object' || Array.isArray(inner) || typeof inner.ok !== 'boolean') {
        throw new CommandExecutionError(`xiaohongshu/unfollow: malformed ${context} payload`);
    }
    return inner;
}

function assertUserId(raw) {
    const input = String(raw ?? '').trim();
    if (/^https?:\/\//i.test(input)) {
        let parsed;
        try {
            parsed = new URL(input);
        } catch {
            throw new ArgumentError('xiaohongshu/unfollow: invalid profile URL');
        }
        if (parsed.protocol !== 'https:' || !isXiaohongshuHost(parsed.hostname)) {
            throw new ArgumentError('xiaohongshu/unfollow: profile URL must be an exact https://*.xiaohongshu.com URL');
        }
        const match = parsed.pathname.match(/^\/user\/profile\/([a-zA-Z0-9]{8,32})\/?$/);
        if (!match) {

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Log into Xiaohongshu in the target browser session and confirm the unfollow button/dialog works manually.
  2. Retry the unfollow — a transient script failure can yield an undefined payload.
  3. Update the library if the site changed its unfollow UI, since requireActionResult's expected payload shape no longer matches what the injected script returns.
  4. Inspect the injected evaluate script for the given context ('click result'/'confirm result') and add logging to see the raw payload before this guard throws.
  5. Ensure you are hitting real xiaohongshu.com pages (host check passes) and not an interstitial/verify page.

Example fix

// before
const res = await page.evaluate(clickScript);
// after
const res = await page.evaluate(clickScript);
if (!res || typeof res !== 'object' || Array.isArray(res) || typeof res.ok !== 'boolean') {
  console.error('raw payload:', JSON.stringify(res));
  throw new Error(`unexpected unfollow payload: ${JSON.stringify(res)}`);
}
Defensive patterns

Strategy: validation

Validate before calling

function isValidActionResult(p) {
  return !!p && typeof p === 'object' && !Array.isArray(p) && typeof p.ok === 'boolean';
}

Type guard

function isActionResult(payload) {
  const inner = unwrapEvaluateResult(payload);
  return typeof inner === 'object' && inner !== null && !Array.isArray(inner) && typeof inner.ok === 'boolean';
}

Try / catch

try {
  await unfollow(userId);
} catch (err) {
  if (String(err.message).includes('malformed') && String(err.message).includes('unfollow')) {
    await reloginIfNeeded();
    return retryUnfollow(userId);
  }
  throw err;
}

Prevention

When it happens

Trigger: clickResult() or confirmResult() evaluates an in-page script whose return value is undefined/null, an array, a non-object, or an object lacking `ok: boolean` — typically because the injected script threw, returned nothing, or the site's DOM/endpoint changed and the script fell through a different path.

Common situations: Xiaohongshu changed the unfollow dialog/endpoint so the injected script's branch never sets `ok`; the evaluate wrapper serialization swallowed an exception and returned undefined; running against a logged-out or risk-control page where the button handler never executes; version drift between the CLI and the site.

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/fd14c5fee393c343. Report an issue: GitHub.