{"record":{"id":"fd14c5fee393c343","repo":"jackwener/OpenCLI","slug":"xiaohongshu-unfollow-malformed-context-payload","errorCode":null,"errorMessage":"xiaohongshu/unfollow: malformed ${context} payload","messagePattern":"xiaohongshu/unfollow: malformed (.+?) payload","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/xiaohongshu/unfollow.js","lineNumber":31,"sourceCode":"import { cli, Strategy } from '@jackwener/opencli/registry';\nimport { ArgumentError, AuthRequiredError, CliError, CommandExecutionError } from '@jackwener/opencli/errors';\nimport { normalizeXhsUserId } from './user-helpers.js';\nimport { unwrapEvaluateResult } from './shared.js';\n\nconst PROFILE_SETTLE_MS = 2500;\nconst MODAL_SETTLE_MS = 1500;\nconst STATE_FLIP_TIMEOUT_MS = 5000;\nconst USER_ID_RE = /^[a-zA-Z0-9]{8,32}$/;\n\nfunction isXiaohongshuHost(hostname) {\n    const host = String(hostname || '').toLowerCase();\n    return host === 'xiaohongshu.com' || host.endsWith('.xiaohongshu.com');\n}\n\nfunction requireActionResult(payload, context) {\n    const inner = unwrapEvaluateResult(payload);\n    if (!inner || typeof inner !== 'object' || Array.isArray(inner) || typeof inner.ok !== 'boolean') {\n        throw new CommandExecutionError(`xiaohongshu/unfollow: malformed ${context} payload`);\n    }\n    return inner;\n}\n\nfunction assertUserId(raw) {\n    const input = String(raw ?? '').trim();\n    if (/^https?:\\/\\//i.test(input)) {\n        let parsed;\n        try {\n            parsed = new URL(input);\n        } catch {\n            throw new ArgumentError('xiaohongshu/unfollow: invalid profile URL');\n        }\n        if (parsed.protocol !== 'https:' || !isXiaohongshuHost(parsed.hostname)) {\n            throw new ArgumentError('xiaohongshu/unfollow: profile URL must be an exact https://*.xiaohongshu.com URL');\n        }\n        const match = parsed.pathname.match(/^\\/user\\/profile\\/([a-zA-Z0-9]{8,32})\\/?$/);\n        if (!match) {","sourceCodeStart":13,"sourceCodeEnd":49,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/xiaohongshu/unfollow.js#L13-L49","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Log into Xiaohongshu in the target browser session and confirm the unfollow button/dialog works manually.","Retry the unfollow — a transient script failure can yield an undefined payload.","Update the library if the site changed its unfollow UI, since requireActionResult's expected payload shape no longer matches what the injected script returns.","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.","Ensure you are hitting real xiaohongshu.com pages (host check passes) and not an interstitial/verify page."],"exampleFix":"// before\nconst res = await page.evaluate(clickScript);\n// after\nconst res = await page.evaluate(clickScript);\nif (!res || typeof res !== 'object' || Array.isArray(res) || typeof res.ok !== 'boolean') {\n  console.error('raw payload:', JSON.stringify(res));\n  throw new Error(`unexpected unfollow payload: ${JSON.stringify(res)}`);\n}","handlingStrategy":"validation","validationCode":"function isValidActionResult(p) {\n  return !!p && typeof p === 'object' && !Array.isArray(p) && typeof p.ok === 'boolean';\n}","typeGuard":"function isActionResult(payload) {\n  const inner = unwrapEvaluateResult(payload);\n  return typeof inner === 'object' && inner !== null && !Array.isArray(inner) && typeof inner.ok === 'boolean';\n}","tryCatchPattern":"try {\n  await unfollow(userId);\n} catch (err) {\n  if (String(err.message).includes('malformed') && String(err.message).includes('unfollow')) {\n    await reloginIfNeeded();\n    return retryUnfollow(userId);\n  }\n  throw err;\n}","preventionTips":["Validate evaluate payloads at call sites before relying on `ok`","Keep the CLI updated with site DOM/endpoint changes","Ensure an active logged-in session and real xiaohongshu.com pages","Log raw payloads to detect shape drift early"],"tags":["xhs","payload-validation","browser-automation","schema-mismatch"],"backgroundTag":"schema-validation-failed","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}