jackwener/OpenCLI · error · CommandExecutionError

xiaohongshu/follow: malformed ${context} payload

Error message

xiaohongshu/follow: malformed ${context} payload

What it means

requireActionResult validates that the payload returned from page.evaluate() unwraps to an object with a boolean ok field; anything else is a CommandExecutionError. It guards the bridge between the CLI and in-page script results. A malformed payload means the injected script did not return the expected { ok: boolean, ... } shape.

Source

Thrown at clis/xiaohongshu/follow.js:35

 */
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 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/follow: 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/follow: invalid profile URL');
        }
        if (parsed.protocol !== 'https:' || !isXiaohongshuHost(parsed.hostname)) {
            throw new ArgumentError('xiaohongshu/follow: 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. Re-run the command — transient navigation/bridge failures often resolve on a second attempt.
  2. Verify the connected browser extension/daemon is current (restart the browser and opencli connection).
  3. Inspect what page.evaluate returns for location/profile actions and confirm it is { ok: boolean, ... }; update unwrapEvaluateResult or the injected script if the shape changed.
  4. Check for page navigation or dialog interrupting the evaluate (add waits before evaluating).

Example fix

// before
const inner = unwrapEvaluateResult(payload);
if (!inner || typeof inner.ok !== 'boolean') throw new CommandExecutionError(`...malformed ${context} payload`);
// after
const inner = unwrapEvaluateResult(payload);
if (!inner || typeof inner !== 'object' || typeof inner.ok !== 'boolean') {
  console.error('raw payload:', payload); // debug the actual shape
  throw new CommandExecutionError(`...malformed ${context} payload`);
}
Defensive patterns

Strategy: type-guard

Type guard

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

Try / catch

try {
  await follow(page, userId);
} catch (err) {
  if (err.code === 'COMMAND_EXEC' && err.message.includes('malformed')) {
    // retry once; then verify bridge/extension health
  }
  throw err;
}

Prevention

When it happens

Trigger: The evaluate() call inside the follow command returned null, undefined, an array, a non-object, or an object without ok === true|false — e.g. the page script threw and returned undefined, the extension bridge wrapped/failed the result, or the script was updated to a different shape.

Common situations: Page navigated away mid-evaluate so the script never ran; browser extension returned an { value: ... } wrapper not handled by unwrapEvaluateResult; a site update replaced the global the script relies on; stale browser bridge after the extension reconnected.

Understand the failure class

Related errors


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