jackwener/OpenCLI · error · CommandExecutionError

twitter_collection_limit_reached

twitter_collection_limit_reached

Error message

twitter_collection_limit_reached: pagination cannot prove completion

What it means

When a page pushes the collected posts to the configured limit, paginateCollection throws instead of stopping gracefully — because cutting off mid-pagination means the run cannot prove it reached the requested 'until' timestamp. The library treats an uncompleted collection as an error so callers never mistake a truncated set for a complete one.

Source

Thrown at clis/twitter/collection.js:270

    };
}

async function paginateCollection({ until, limit, maxPages = MAX_USER_TWEETS_PAGES, fetchPage, wait }) {
    const seen = new Set();
    const seenCursors = new Set();
    const posts = [];
    let cursor = null;
    let oldestSeenAt = null;
    for (let pageIndex = 0; pageIndex < maxPages; pageIndex++) {
        if (pageIndex > 0 && wait) await wait();
        const payload = await fetchPage(cursor, USER_TWEETS_PAGE_SIZE);
        if (payload?.error) {
            throw new CommandExecutionError(`twitter_collection_request_error: UserTweets returned ${payload.error}`);
        }
        const [pagePosts, nextCursor] = parseCollectionPage(payload, seen);
        for (const post of pagePosts) {
            if (posts.length >= limit) {
                throw new CommandExecutionError('twitter_collection_limit_reached: pagination cannot prove completion');
            }
            const createdAt = parseCreatedAt(post);
            if (!oldestSeenAt || createdAt < oldestSeenAt) oldestSeenAt = createdAt;
            posts.push(post);
            if (createdAt <= until) {
                return {
                    posts,
                    receipt: completedReceipt('time_boundary_reached', until, pageIndex + 1, oldestSeenAt),
                };
            }
        }
        if (!nextCursor) {
            return {
                posts,
                receipt: completedReceipt('cursor_exhausted', until, pageIndex + 1, oldestSeenAt),
            };
        }
        if (nextCursor === cursor || seenCursors.has(nextCursor)) {

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Increase the limit option so it exceeds the expected post count between now and 'until'.
  2. Move the 'until' cutoff closer to the present to reduce the number of posts that must be walked.
  3. Incremental collection: store the newest timestamp seen and use it as the next 'until' so each run walks fewer posts.
  4. Accept partial data explicitly (catch this error and keep posts accumulated so far, understanding completion is unproven).
  5. Raise maxPages in tandem with limit so pagination is actually allowed to reach the cutoff.

Example fix

// before
await cliRun({ limit: 100, until: sevenDaysAgo });
// after
await cliRun({ limit: 5000, until: oneHourAgo }); // limit large enough to cover posts since cutoff
Defensive patterns

Strategy: validation

Validate before calling

const estimate = (now - until) / averageIntervalMs;
if (estimate > limit) {
  console.warn(`limit ${limit} likely insufficient (~${Math.ceil(estimate)} posts expected)`);
}

Try / catch

try {
  const { posts, receipt } = await collection(...);
} catch (err) {
  if (String(err.message).startsWith('twitter_collection_limit_reached')) {
    // accept partial data explicitly, or rerun with larger limit / nearer until
  } else throw err;
}

Prevention

When it happens

Trigger: The user's limit (or default) is smaller than the number of posts published by the account since the 'until' cutoff — pagination would need to stop mid-run without reaching until.

Common situations: Collecting the last N hours from a very high-volume account with a small limit; reusing a limit tuned for one account against a far more prolific account; passing an 'until' far in the past so the whole timeline must be walked.

Related errors


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