{"record":{"id":"74c692901d1a25f8","repo":"jackwener/OpenCLI","slug":"xianyu-messages-accepts-either-item-id-user-id-or","errorCode":null,"errorMessage":"xianyu messages accepts either item_id/user_id or --rank, not both","messagePattern":"xianyu messages accepts either item_id/user_id or --rank, not both","errorType":"validation","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"clis/xianyu/messages.js","lineNumber":37,"sourceCode":"    access: 'read',\n    description: '读取指定闲鱼私信会话的最近聊天内容',\n    domain: 'www.goofish.com',\n    strategy: Strategy.COOKIE,\n    navigateBefore: false,\n    browser: true,\n    args: [\n        { name: 'item_id', positional: true, help: '闲鱼商品 item_id' },\n        { name: 'user_id', positional: true, help: '聊一聊对方的 user_id / peerUserId' },\n        { name: 'limit', type: 'int', default: DEFAULT_MESSAGE_LIMIT, help: 'Number of visible messages to return' },\n        { name: 'rank', type: 'int', default: 0, help: 'Conversation rank from xianyu inbox; clicks the visible row instead of requiring IDs' },\n    ],\n    columns: ['index', 'peer_name', 'item_title', 'message', 'item_id', 'peer_user_id', 'url'],\n    func: async (page, kwargs) => {\n        const hasItemId = kwargs.item_id != null && kwargs.item_id !== '';\n        const hasUserId = kwargs.user_id != null && kwargs.user_id !== '';\n        const rank = normalizeRank(kwargs.rank);\n        if (rank > 0 && (hasItemId || hasUserId)) {\n            throw new ArgumentError('xianyu messages accepts either item_id/user_id or --rank, not both');\n        }\n        if (rank === 0 && hasItemId !== hasUserId) {\n            throw new ArgumentError('xianyu messages requires both item_id and user_id, or --rank from xianyu inbox');\n        }\n        if (rank === 0 && !hasItemId && !hasUserId) {\n            throw new ArgumentError('xianyu messages requires item_id/user_id or --rank from xianyu inbox');\n        }\n        const hasIds = hasItemId && hasUserId;\n        const itemId = hasIds ? normalizeNumericId(kwargs.item_id, 'item_id', '1038951278192') : '';\n        const userId = hasIds ? normalizeNumericId(kwargs.user_id, 'user_id', '3650092411') : '';\n        const limit = normalizeLimit(kwargs.limit, DEFAULT_MESSAGE_LIMIT, MAX_MESSAGE_LIMIT, 'messages --limit');\n        let url = '';\n        if (hasIds) {\n            url = buildChatUrl(itemId, userId);\n            await page.goto(url);\n        } else {\n            if (!page.getCurrentUrl || !/https:\\/\\/www\\.goofish\\.com\\/im\\b/.test(await page.getCurrentUrl())) {\n                await page.goto('https://www.goofish.com/im');","sourceCodeStart":19,"sourceCodeEnd":55,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/xianyu/messages.js#L19-L55","documentation":"The `xianyu messages` command supports two mutually exclusive targeting modes: an explicit item_id+user_id pair, or a `--rank` index pointing at a conversation from a prior `xianyu inbox` listing. Passing both at once is ambiguous, so ArgumentError is thrown from clis/xianyu/messages.js:37. It is an input-validation error, not a runtime/API failure.","triggerScenarios":"Invoking the messages command with --rank greater than 0 while also supplying item_id and/or user_id, e.g. `xianyu messages --rank 2 --item_id 123 --user_id 456` or `--rank 1 --item_id 123`.","commonSituations":"Scripting a flow that iterates inbox results by rank but forgot to remove leftover item_id/user_id flags from a previous invocation; copy-pasting example commands and merging both argument styles; templated commands where optional kwargs are filled in unconditionally.","solutions":["Pick one targeting mode: either pass --rank N (from xianyu inbox output) OR pass both --item_id and --user_id, never both styles.","Remove the --rank flag if you intend to address the conversation by IDs.","Remove --item_id/--user_id if you intend to pick the Nth inbox conversation by rank.","In wrapper scripts, conditionally build the argument list based on which mode was selected."],"exampleFix":"// before\nawait cli.run(['xianyu', 'messages', '--rank', '2', '--item_id', itemId, '--user_id', userId]);\n\n// after\nconst args = byRank\n  ? ['xianyu', 'messages', '--rank', String(rank)]\n  : ['xianyu', 'messages', '--item_id', itemId, '--user_id', userId];\nawait cli.run(args);","handlingStrategy":"validation","validationCode":"const modes = [rank > 0, Boolean(itemId || userId)].filter(Boolean).length;\nif (modes > 1) throw new Error('use --rank OR item_id+user_id, not both');","typeGuard":null,"tryCatchPattern":"try {\n  await cli.run(args);\n} catch (e) {\n  if (e instanceof ArgumentError && /not both/.test(e.message)) {\n    console.error('Fix invocation: drop --rank or drop --item_id/--user_id');\n  } else throw e;\n}","preventionTips":["Build CLI args in a single helper that enforces one targeting mode.","Never forward leftover flags between invocations in scripts.","Document the two targeting modes where the command is wrapped."],"tags":["argument-validation","cli-usage","xianyu"],"backgroundTag":"mutually-exclusive-arguments","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}