jackwener/OpenCLI · error · CommandExecutionError

Twitter UserMedia pagination reached the ${MAX_PAGINATION_PA

Error message

Twitter UserMedia pagination reached the ${MAX_PAGINATION_PAGES}-page safety cap before collecting ${limit} media items

What it means

UserMedia pagination is capped at MAX_PAGINATION_PAGES iterations as a runaway-loop guard. If the loop ends having collected fewer items than --limit while the last response still advertised a next cursor, the command throws CommandExecutionError explaining the safety cap was reached before collecting the requested count.

Source

Thrown at clis/twitter/download.js:410

          if (!r.ok) return { ok: false, status: r.status };
          return { ok: true, payload: await r.json() };
        } catch (err) {
          return { ok: false, error: err?.message ?? String(err) };
        }
        }`)));
        const { items, nextCursor } = parseUserMedia(data, seen);
        all.push(...items);
        hasMorePages = Boolean(nextCursor);
        if (!nextCursor) break;
        if (nextCursor === cursor) {
            throw new CommandExecutionError('Twitter UserMedia pagination returned the same cursor twice');
        }
        cursor = nextCursor;
    }

    if (all.length === 0) throw new EmptyResultError(`@${username} has no media`, 'Account may be private, suspended, or have no media posts');
    if (all.length < limit && hasMorePages) {
        throw new CommandExecutionError(`Twitter UserMedia pagination reached the ${MAX_PAGINATION_PAGES}-page safety cap before collecting ${limit} media items`);
    }

    const trimmed = all.slice(0, limit);
    return downloadTwitterMedia(trimmed, {
        output,
        subdir: username,
        cookies: formatCookieHeader(cookies),
        browserCookies: cookies,
        filenamePrefix: username,
        ytdlpExtraArgs: ['--merge-output-format', 'mp4'],
    });
}

async function downloadSingleTweet(page, tweetUrl, output) {
    const target = parseTweetUrl(tweetUrl);
    await page.goto(target.url);
    await page.wait(3);
    const items = unwrapBrowserResult(await page.evaluate(`

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Lower --limit to a value reachable within MAX_PAGINATION_PAGES pages
  2. Re-run the command; transient truncation may resolve on retry
  3. Raise MAX_PAGINATION_PAGES in the source if you maintain a fork and genuinely need deeper pagination

Example fix

// before
opencli twitter download @jack --limit 500
// after
opencli twitter download @jack --limit 100
Defensive patterns

Strategy: fallback

Validate before calling

const MAX_DELIVERABLE = MAX_PAGINATION_PAGES * ITEMS_PER_PAGE;
if (limit > MAX_DELIVERABLE) {
  limit = MAX_DELIVERABLE;
  console.warn(`Limit reduced to ${limit} due to pagination cap`);
}

Try / catch

try {
  return await cmd();
} catch (err) {
  if (err.message.includes('safety cap')) {
    return runWithLowerLimit(err); // retry with a smaller --limit
  }
  throw err;
}

Prevention

When it happens

Trigger: Requesting a large --limit (e.g. 500) on an account with abundant media where MAX_PAGINATION_PAGES pages of fetchCount-sized batches are insufficient, or pages returning fewer items than requested due to filtering/rate limiting.

Common situations: Setting --limit higher than what the page cap can deliver; Twitter returning truncated pages under rate limiting; duplicated items being deduplicated by `seen` so progress per page shrinks.

Related errors


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