jackwener/OpenCLI · error · ArgumentError

twitter search --limit must be a positive integer

Error message

twitter search --limit must be a positive integer

What it means

ArgumentError raised when the --limit value is not a positive integer. The library validates Number(kwargs.limit) is an integer > 0 before issuing the search request.

Source

Thrown at clis/twitter/search.js:285

    browser: true,
    args: [
        { name: 'query', type: 'string', required: true, positional: true, help: 'Search query. Raw X operators (e.g. "exact phrase", #tag, OR, lang:en, since:YYYY-MM-DD, from:, since:) are passed through unchanged.' },
        { name: 'filter', type: 'string', default: 'top', choices: ['top', 'live'], help: 'Legacy alias for --product. Kept for backwards compatibility; if --product is set it wins.' },
        { name: 'product', type: 'string', choices: PRODUCT_CHOICES, help: 'Which X search tab to read: top (default), live (Latest), photos, videos. Maps to the f= URL param.' },
        { name: 'from', type: 'string', help: 'Restrict to tweets authored by <user>. Leading @ is stripped. Equivalent to appending `from:<user>` to the query.' },
        { name: 'has', type: 'string', choices: HAS_CHOICES, help: 'Restrict to tweets that have media|images|videos|links|replies. Maps to X\'s `filter:<has>` operator.' },
        { name: 'exclude', type: 'string', choices: EXCLUDE_CHOICES, help: 'Exclude tweets matching <type>: replies|retweets|media|links. Maps to X\'s `-filter:<x>` operator (retweets → -filter:nativeretweets).' },
        { name: 'limit', type: 'int', default: 15, help: 'Maximum number of tweets to return (default 15). Result count after server-side filtering.' },
        { name: 'top-by-engagement', type: 'int', default: 0, help: 'When set to N>0, re-rank the results by weighted engagement (likes×1 + retweets×3 + replies×2 + bookmarks×5 + log10(views+1)×0.5) and return the top N. Default 0 keeps X\'s native ordering.' },
    ],
    columns: ['id', 'author', 'bio', 'text', 'created_at', 'likes', 'views', 'url', 'has_media', 'media_urls', 'media_posters', 'card', 'quoted_tweet'],
    func: async (page, kwargs) => {
        const finalQuery = buildSearchQuery(kwargs.query, kwargs);
        if (!finalQuery) {
            throw new ArgumentError('twitter search query is empty', 'Provide a non-empty <query>, or use at least one of --from / --has / --exclude.');
        }
        if (!Number.isInteger(Number(kwargs.limit)) || Number(kwargs.limit) <= 0) {
            throw new ArgumentError('twitter search --limit must be a positive integer', 'Example: opencli twitter search opencli --limit 15');
        }
        const cookies = await page.getCookies({ url: 'https://x.com' });
        const ct0 = cookies.find((c) => c.name === 'ct0')?.value || null;
        if (!ct0) throw new AuthRequiredError('x.com', 'Not logged into x.com (no ct0 cookie)');
        await page.goto('https://x.com/home', { waitUntil: 'load', settleMs: 1000 });
        const operation = await resolveTwitterOperationMetadata(page, 'SearchTimeline', SEARCH_TIMELINE_OPERATION);
        const headers = JSON.stringify({
            'Authorization': `Bearer ${decodeURIComponent(TWITTER_BEARER_TOKEN)}`,
            'X-Csrf-Token': ct0,
            'X-Twitter-Auth-Type': 'OAuth2Session',
            'X-Twitter-Active-User': 'yes',
            'Content-Type': 'application/json',
        });
        const product = resolveSearchProduct(kwargs);
        const results = [];
        const seen = new Set();
        let cursor = null;
        // Runaway guard only; --limit and cursor exhaustion control normal pagination.

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Pass a whole number greater than 0, e.g. --limit 15
  2. Remove units/decimals from the value
  3. Ensure the CI variable supplying the limit is set and numeric

Example fix

// before
opencli twitter search opencli --limit 0
// after
opencli twitter search opencli --limit 15
Defensive patterns

Strategy: validation

Validate before calling

function isValidLimit(v) { const n = Number(v); return Number.isInteger(n) && n > 0; }
if (!isValidLimit(process.env.SEARCH_LIMIT ?? kwargs.limit)) throw new Error('limit must be a positive integer');

Type guard

function isPositiveInt(v) { return Number.isInteger(Number(v)) && Number(v) > 0; }

Try / catch

try {
  await opencli.twitter.search(q, { limit });
} catch (e) {
  if (e.name === 'ArgumentError' && /--limit/.test(e.message)) {
    console.error('Use e.g. --limit 15');
  } else throw e;
}

Prevention

When it happens

Trigger: `--limit 0`, `--limit -5`, `--limit abc`, `--limit 12.5`, or limit passed as an empty string — anything failing Number.isInteger(Number(v)) || v <= 0.

Common situations: Typos on the command line, copying fractional defaults like '10.0', environment/CI variables expanding to empty, or passing limit as a string with units ('15 tweets').

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


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