jackwener/OpenCLI · error · ArgumentError

--top-by-engagement cannot be combined with --output-file

Error message

--top-by-engagement cannot be combined with --output-file

What it means

The bookmarks CLI validates flag combinations before doing any work. --top-by-engagement re-ranks in-memory results and returns top N, while --output-file streams pages to JSONL; combining them is unsupported, so the command throws this ArgumentError immediately.

Source

Thrown at clis/twitter/bookmarks.js:193

    args: [
        { name: 'limit', type: 'int', default: 20, help: 'Maximum number of bookmarks to return (default 20). Ignored when --all is set.' },
        { name: 'all', type: 'bool', default: false, help: 'Fetch all bookmark pages until exhausted. Prefer --output-file for large archives.' },
        { name: 'resume-file', type: 'string', help: 'Resume file for long-running all-pages bookmark syncs.' },
        { name: 'output-file', type: 'string', help: 'Write all-page results to JSONL. Requires --all and --resume-file.' },
        { name: 'max-pages', type: 'int', help: `Optional pagination safety cap (default ${DEFAULT_MAX_PAGINATION_PAGES}; raised automatically with --all).` },
        { name: 'top-by-engagement', type: 'int', default: 0, help: 'When set to N>0, re-rank the bookmarks 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 API\'s native (saved-time) ordering. Incompatible with --output-file.' },
    ],
    columns: ['id', 'author', 'text', 'likes', 'retweets', 'bookmarks', 'created_at', 'url', 'has_media', 'media_urls', 'media_posters'],
    func: async (page, kwargs) => {
        const fetchAll = Boolean(kwargs.all);
        const limit = fetchAll ? Number.POSITIVE_INFINITY : (kwargs.limit || 20);
        const resumeFile = resolveOptionalFilePath(kwargs['resume-file'], '--resume-file');
        const outputFile = resolveOptionalFilePath(kwargs['output-file'], '--output-file');
        const useOutputFile = Boolean(fetchAll && outputFile);
        const maxPages = resolveMaxPages(kwargs, fetchAll);
        const topByEngagement = Number(kwargs['top-by-engagement'] || 0);
        if (useOutputFile && topByEngagement > 0) {
            throw new ArgumentError('--top-by-engagement cannot be combined with --output-file');
        }
        if (outputFile && !fetchAll) {
            throw new ArgumentError('--output-file requires --all');
        }
        if (resumeFile && !fetchAll) {
            throw new ArgumentError('--resume-file requires --all');
        }
        if (outputFile && !resumeFile) {
            throw new ArgumentError('--output-file requires --resume-file so partial archives remain resumable');
        }
        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)');
        const queryId = await resolveTwitterQueryId(page, 'Bookmarks', BOOKMARKS_QUERY_ID);
        const headers = JSON.stringify({
            'Authorization': `Bearer ${decodeURIComponent(TWITTER_BEARER_TOKEN)}`,
            'X-Csrf-Token': ct0,

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Remove --top-by-engagement when archiving with --output-file.
  2. Or drop --output-file/--resume-file and run in-memory with --top-by-engagement N (optionally with --all).
  3. Do the ranking yourself afterwards on the JSONL archive (likes×1 + retweets×3 + replies×2 + bookmarks×5 + log10(views+1)×0.5).

Example fix

// before
cli twitter bookmarks --all --output-file a.jsonl --resume-file r.json --top-by-engagement 10
// after (choose one mode)
cli twitter bookmarks --all --output-file a.jsonl --resume-file r.json
# or
cli twitter bookmarks --all --top-by-engagement 10
Defensive patterns

Strategy: validation

Validate before calling

const flags = ['--all', '--output-file', a, '--resume-file', r, '--top-by-engagement', '10'];
if (flags.includes('--output-file') && Number(kwargs['top-by-engagement'] || 0) > 0) {
  throw new Error('drop --top-by-engagement when archiving with --output-file');
}

Type guard

null

Try / catch

try {
  await run(args);
} catch (e) {
  if (String(e.message).includes('--top-by-engagement cannot be combined with --output-file')) {
    const cleaned = args.filter((f, i) => f !== '--top-by-engagement' && args[i - 1] !== '--top-by-engagement');
    await run(cleaned);
  } else throw e;
}

Prevention

When it happens

Trigger: Invoking `twitter bookmarks --all --output-file archive.jsonl --resume-file r.json --top-by-engagement 10`.

Common situations: Assuming ranking works with JSONL archiving; copying flags from two different example commands into one invocation.

Related errors


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