jackwener/OpenCLI · error · ArgumentError

twitter search query is empty

Error message

twitter search query is empty

What it means

ArgumentError thrown by the search command when the final assembled query string is empty — i.e. the positional <query> was empty AND no --from/--has/--exclude options contributed any terms. X's search endpoint requires a non-empty query, so the library fails fast.

Source

Thrown at clis/twitter/search.js:282

    description: 'Search Twitter/X for tweets, with optional --from / --has / --exclude / --product filters mapped to X\'s search operators',
    domain: 'x.com',
    strategy: Strategy.COOKIE,
    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 = [];

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Pass a non-empty positional <query>
  2. Or supply at least one filter: --from, --has, or --exclude
  3. Check shell quoting/variable expansion so the query is not stripped to an empty string

Example fix

// before
opencli twitter search ''
// after
opencli twitter search 'opencli' --limit 15
// or flag-only search:
opencli twitter search '' --from jack  # if supported spelling of flags is used
Defensive patterns

Strategy: validation

Validate before calling

function hasSearchInput(kwargs) {
  return Boolean(String(kwargs.query ?? '').trim() || kwargs.from || kwargs.has || kwargs.exclude);
}
if (!hasSearchInput(kwargs)) throw new Error('Provide a query or --from/--has/--exclude');

Type guard

function isNonEmptyString(v) { return typeof v === 'string' && v.trim().length > 0; }

Try / catch

try {
  await opencli.twitter.search(query);
} catch (e) {
  if (e.name === 'ArgumentError' && /empty/.test(e.message)) {
    console.error('Query was empty; supply <query> or filter flags');
  } else throw e;
}

Prevention

When it happens

Trigger: `opencli twitter search ''`, calling search programmatically with kwargs.query = null/undefined and no filter flags, or quoting issues so the shell passes an empty string as the query.

Common situations: Script variables that expand to empty strings, forgetting the positional query while intending a --from-only search but misspelling the flag name, or piping empty input.

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/ddd19bea3a8635da. Report an issue: GitHub.