{"record":{"id":"d357698e2e2a5ef8","repo":"jackwener/OpenCLI","slug":"invalid-listid-json-stringify-kwargs-listid-d35769","errorCode":null,"errorMessage":"Invalid listId: ${JSON.stringify(kwargs.listId)}. Expected a numeric ID (see `opencli twitter lists`).","messagePattern":"Invalid listId: (.+?)\\. Expected a numeric ID \\(see `opencli twitter lists`\\)\\.","errorType":"validation","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/twitter/list-tweets.js","lineNumber":132,"sourceCode":"\ncli({\n    site: 'twitter',\n    name: 'list-tweets',\n    access: 'read',\n    description: 'Fetch tweets from a Twitter/X list timeline',\n    domain: 'x.com',\n    strategy: Strategy.COOKIE,\n    browser: true,\n    args: [\n        { name: 'listId', positional: true, type: 'string', required: true, help: 'Numeric ID of a Twitter/X list (e.g. from `opencli twitter lists`)' },\n        { name: 'limit', type: 'int', default: 50 },\n        { name: 'top-by-engagement', type: 'int', default: 0, help: 'When set to N>0, re-rank the list timeline by weighted engagement (likes×1 + retweets×3 + replies×2 + bookmarks×5 + log10(views+1)×0.5) and return the top N. Default 0 keeps the list\\'s native (recency) ordering.' },\n    ],\n    columns: ['id', 'author', 'bio', 'text', 'likes', 'retweets', 'replies', 'created_at', 'url', 'has_media', 'media_urls', 'media_posters', 'card', 'quoted_tweet'],\n    func: async (page, kwargs) => {\n        const listId = String(kwargs.listId || '').trim();\n        if (!listId || !/^\\d+$/.test(listId)) {\n            throw new CommandExecutionError(`Invalid listId: ${JSON.stringify(kwargs.listId)}. Expected a numeric ID (see \\`opencli twitter lists\\`).`);\n        }\n        const limit = kwargs.limit || 50;\n        const cookies = await page.getCookies({ url: 'https://x.com' });\n        const ct0 = cookies.find((c) => c.name === 'ct0')?.value || null;\n        if (!ct0)\n            throw new AuthRequiredError('x.com', 'Not logged into x.com (no ct0 cookie)');\n        // opencli >=1.7.x wraps primitive page.evaluate returns as { session, data: <value> }.\n        // Without unwrap, the string queryId becomes \"[object Object]\" when interpolated into the URL,\n        // causing HTTP 400 \"queryId may have expired\".\n        const unwrap = (v) => (v && typeof v === 'object' && 'session' in v && 'data' in v ? v.data : v);\n        const queryIdRaw = await page.evaluate(`async () => {\n            try {\n                const ghResp = await fetch('https://raw.githubusercontent.com/fa0311/twitter-openapi/refs/heads/main/src/config/placeholder.json');\n                if (ghResp.ok) {\n                    const data = await ghResp.json();\n                    const entry = data['${OPERATION_NAME}'];\n                    if (entry && entry.queryId) return entry.queryId;\n                }","sourceCodeStart":114,"sourceCodeEnd":150,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/twitter/list-tweets.js#L114-L150","documentation":"The `twitter list-tweets` command requires listId to be a non-empty string of digits (X list IDs are large numeric identifiers). Empty, non-numeric, or float-form input is rejected immediately with a CommandExecutionError before any network work.","triggerScenarios":"Calling the command with listId missing/empty ('' or undefined), with a non-numeric value ('my-list'), a float ('123.0' fails? no — '.' fails the ^\\d+$ test), a number in scientific notation, or an object; String() is applied first, so only digit-only strings pass.","commonSituations":"Passing a list name instead of an ID; copying the list's URL slug/owner handle instead of the numeric id; JSON tooling serializing the big id as a float (1.9e18) or quoted-with-spaces value; forgetting the --listId flag so kwargs.listId is undefined.","solutions":["Get the numeric ID with `opencli twitter lists` and pass it as-is, e.g. --listId 1234567890123456789","If the id comes from JSON, keep it as a string — large ids lose precision as JS numbers","Trim whitespace / strip URL prefixes: use only the digits from an x.com/i/lists/<id> URL","Fix the calling script so the flag/field is actually populated (undefined → this error)"],"exampleFix":"// before\nconst listId = BigInt(rawId); // serializes oddly / may be NaN-ish\nawait run('twitter', 'list-tweets', { listId });\n// after\nconst listId = String(rawId).trim();\nif (!/^\\d+$/.test(listId)) throw new Error(`listId must be numeric digits, got: ${rawId}`);\nawait run('twitter', 'list-tweets', { listId });","handlingStrategy":"validation","validationCode":"function validListId(v){ const s = String(v ?? '').trim(); return /^\\d+$/.test(s) ? s : null; }\nconst listId = validListId(kwargs.listId);\nif (!listId) throw new Error(`listId must be numeric digits, got ${JSON.stringify(kwargs.listId)}`);","typeGuard":"const isNumericId = (v) => typeof v === 'string' && /^\\d+$/.test(v.trim());","tryCatchPattern":"try {\n  await run('twitter', 'list-tweets', { listId });\n} catch (e) {\n  if (String(e.message).startsWith('Invalid listId')) {\n    const lists = await run('twitter', 'lists', {}); // help the user resolve the real id\n    console.error('Pick a numeric id from:', lists.map(l => `${l.id} ${l.name}`));\n  } else throw e;\n}","preventionTips":["Always source listId from `opencli twitter lists`, never from list names or URL slugs","Keep big ids as strings end-to-end (JS Number loses precision above 2^53)","Validate with /^\\d+$/ before calling","Check flag spelling — undefined kwargs.listId triggers this error"],"tags":["validation","input-error","cli"],"backgroundTag":"invalid-argument-format","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}