jackwener/OpenCLI · error · ArgumentError

xianyu reply requires both item_id and user_id, or --rank fr

Error message

xianyu reply requires both item_id and user_id, or --rank from xianyu inbox

What it means

Without --rank, reply requires BOTH item_id and user_id to build the chat URL. Providing exactly one of them (hasItemId !== hasUserId) is rejected with this ArgumentError, since a partial pair cannot form a goofish chat URL. Thrown at clis/xianyu/reply.js:29-31.

Source

Thrown at clis/xianyu/reply.js:30

    strategy: Strategy.COOKIE,
    navigateBefore: false,
    browser: true,
    args: [
        { name: 'item_id', positional: true, help: '闲鱼商品 item_id' },
        { name: 'user_id', positional: true, help: '聊一聊对方的 user_id / peerUserId' },
        { name: 'text', required: true, help: 'Message text to send' },
        { name: 'rank', type: 'int', default: 0, help: 'Conversation rank from xianyu inbox; clicks the visible row instead of requiring IDs' },
    ],
    columns: ['status', 'peer_name', 'item_title', 'price', 'location', 'message'],
    func: async (page, kwargs) => {
        const hasItemId = kwargs.item_id != null && kwargs.item_id !== '';
        const hasUserId = kwargs.user_id != null && kwargs.user_id !== '';
        const rank = normalizeRank(kwargs.rank);
        if (rank > 0 && (hasItemId || hasUserId)) {
            throw new ArgumentError('xianyu reply accepts either item_id/user_id or --rank, not both');
        }
        if (rank === 0 && hasItemId !== hasUserId) {
            throw new ArgumentError('xianyu reply requires both item_id and user_id, or --rank from xianyu inbox');
        }
        if (rank === 0 && !hasItemId && !hasUserId) {
            throw new ArgumentError('xianyu reply requires item_id/user_id or --rank from xianyu inbox');
        }
        const hasIds = hasItemId && hasUserId;
        const itemId = hasIds ? normalizeNumericId(kwargs.item_id, 'item_id', '1038951278192') : '';
        const userId = hasIds ? normalizeNumericId(kwargs.user_id, 'user_id', '3650092411') : '';
        const text = requireText(kwargs.text, 'xianyu reply --text');
        const url = hasIds ? buildChatUrl(itemId, userId) : '';
        if (hasIds) {
            await page.goto(url);
        } else {
            if (!page.getCurrentUrl || !/https:\/\/www\.goofish\.com\/im\b/.test(await page.getCurrentUrl())) {
                await page.goto('https://www.goofish.com/im');
            }
        }
        await page.wait(2);
        if (rank > 0) {

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Supply both positional IDs: `xianyu reply <item_id> <user_id> --text '...'`.
  2. If only the conversation position is known, use `--rank N` from `xianyu inbox` output instead of a partial ID pair.
  3. Fix the upstream data source so user_id is populated before invoking reply.

Example fix

// before: only item_id
xianyu reply 1038951278192 --text "still available?"
// after: both IDs (or --rank)
xianyu reply 1038951278192 3650092411 --text "still available?"
Defensive patterns

Strategy: validation

Validate before calling

const hasOne = (v) => v != null && v !== '';
const a = hasOne(kwargs.item_id), b = hasOne(kwargs.user_id);
if (a !== b) throw new Error('xianyu reply needs BOTH item_id and user_id (or use --rank).');

Try / catch

try {
  await reply(kwargs);
} catch (e) {
  if (String(e.message).includes('requires both item_id and user_id')) {
    if (!hasOne(kwargs.user_id)) throw new Error('Lookup user_id from the inbox before replying.');
    if (!hasOne(kwargs.item_id)) throw new Error('Lookup item_id from the conversation before replying.');
  }
  throw e;
}

Prevention

When it happens

Trigger: Invoking `xianyu reply <item_id> --text ...` (user_id missing) or `xianyu reply <item_id> <empty-user_id> ...` — one ID set, the other null/empty, rank === 0.

Common situations: Copy-pasting only the item URL and forgetting the peer's user_id; user_id field empty in a database record feeding the CLI; confusing this command's two-positional-args signature with single-ID chat CLIs.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


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