jackwener/OpenCLI · error · CommandExecutionError
xiaohongshu/unfollow: malformed current-url payload
Error message
xiaohongshu/unfollow: malformed current-url payload
What it means
After navigating to the profile URL and settling, the command reads location.href via page.evaluate and unwraps it with unwrapEvaluateResult. If the unwrapped value is not a string, the browser bridge returned something unexpected, so this CommandExecutionError is thrown to fail fast rather than call new URL() on garbage.
Source
Thrown at clis/xiaohongshu/unfollow.js:211
required: true,
positional: true,
help: 'User ID (e.g. 5d8f88dc0000000001005d3a) or profile URL',
},
],
columns: ['status', 'user_id', 'url'],
func: async (page, kwargs) => {
if (!page) {
throw new CommandExecutionError('Browser session required for xiaohongshu unfollow');
}
try {
const userId = assertUserId(kwargs['user-id']);
const url = `https://www.xiaohongshu.com/user/profile/${userId}`;
await page.goto(url);
await page.wait({ time: PROFILE_SETTLE_MS / 1000 });
const hrefRaw = unwrapEvaluateResult(await page.evaluate('() => location.href'));
if (typeof hrefRaw !== 'string') {
throw new CommandExecutionError('xiaohongshu/unfollow: malformed current-url payload');
}
const parsedHref = new URL(hrefRaw);
if (parsedHref.protocol !== 'https:' || !isXiaohongshuHost(parsedHref.hostname)) {
throw new CommandExecutionError(
`xiaohongshu/unfollow: expected Xiaohongshu profile host, got ${parsedHref.hostname}`,
);
}
if (/\/login(?:[/?#]|$)/i.test(parsedHref.pathname)) {
throw new AuthRequiredError('www.xiaohongshu.com');
}
const currentProfile = parsedHref.pathname.match(/^\/user\/profile\/([a-zA-Z0-9]{8,32})\/?$/);
if (currentProfile?.[1] !== userId) {
throw new CommandExecutionError(
`xiaohongshu/unfollow: expected profile ${userId}, got ${parsedHref.pathname}`,
);
}
// Step 1: click 已关注 (idempotent — bails out if 关注 is visible)View on GitHub (pinned to 49907e53dc)
Solutions
- Update the CLI/driver packages so page.evaluate and unwrapEvaluateResult use the same result-wrapping convention
- Confirm you are using the library's own page object/driver, not a custom evaluate wrapper that changes return shapes
- Re-run the command — a transient page crash or navigation race can produce a non-string result; also increase settle time if the page was still loading
- Inspect what page.evaluate('() => location.href') actually returns in your environment and adapt (it must be a plain string)
Example fix
// before
const href = await myWrapper.evaluate(page, '() => location.href'); // returns { value: '...' }
// after
const href = unwrapEvaluateResult(await page.evaluate('() => location.href')); // string Defensive patterns
Strategy: try-catch
Type guard
function isString(v) { return typeof v === 'string'; }
// usage: const href = unwrapEvaluateResult(raw); if (!isString(href)) fallBackOrRetry(); Try / catch
try { await cli.unfollow({ 'user-id': id }); } catch (e) { if (String(e.message).includes('malformed current-url payload')) { /* retry once with the library's own driver, or upgrade library versions */ } else throw e; } Prevention
- Use the library's own page/driver so evaluate result shapes match
- Keep the CLI and driver packages on compatible versions
- Retry transient navigation failures instead of treating them as fatal
- Log the raw evaluate result when debugging wrapper integrations
When it happens
Trigger: page.evaluate returning a non-string payload — e.g. the wrapper returned {value: ...}, an array, undefined, or a serialized error object instead of a raw string; a custom/driver-specific evaluate that wraps results; a proxy or patched evaluate injecting metadata; navigation failing so the evaluate result is an error object.
Common situations: Using a different driver/automation layer whose evaluate result shape differs from what the CLI expects; library version mismatch where unwrapEvaluateResult conventions changed; page crashed or was closed mid-evaluate so the promise resolves with a non-string sentinel.
Understand the failure class
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- Unexpected Claude probe: ${JSON.stringify(result)}
- Failed to send message
- ${message}: malformed GeoGebra result
- Failed to detect GeoGebra applet: ${err?.message || err}
- ggbApplet not available after waiting. Make sure the GeoGebr
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/fc8ad2b383066fdc.
Report an issue: GitHub.