jackwener/OpenCLI · error · CommandExecutionError

twitter_collection_page_guard_hit

twitter_collection_page_guard_hit

Error message

twitter_collection_page_guard_hit: pagination cannot prove completion

What it means

If the for-loop over pageIndex completes maxPages iterations without reaching 'until' or exhausting the cursor, the pagination guard trips: the page budget ran out before completion could be proven. The library throws rather than returning an unverified, potentially gap-filled post set.

Source

Thrown at clis/twitter/collection.js:297

                };
            }
        }
        if (!nextCursor) {
            return {
                posts,
                receipt: completedReceipt('cursor_exhausted', until, pageIndex + 1, oldestSeenAt),
            };
        }
        if (nextCursor === cursor || seenCursors.has(nextCursor)) {
            throw new CommandExecutionError('twitter_collection_repeated_cursor: pagination cannot prove completion');
        }
        if (posts.length >= limit) {
            throw new CommandExecutionError('twitter_collection_limit_reached: pagination cannot prove completion');
        }
        seenCursors.add(nextCursor);
        cursor = nextCursor;
    }
    throw new CommandExecutionError('twitter_collection_page_guard_hit: pagination cannot prove completion');
}

cli({
    site: 'twitter',
    name: 'collection',
    access: 'read',
    description: 'Fetch a user timeline with relationship facts and a bounded completion receipt.',
    domain: 'x.com',
    strategy: Strategy.COOKIE,
    browser: true,
    args: [
        { name: 'username', type: 'string', positional: true, required: true, help: 'Twitter screen name (with or without @).' },
        { name: 'until', type: 'string', required: true, help: 'RFC3339 lower time boundary that must be reached or exhausted.' },
        { name: 'limit', type: 'int', default: MAX_USER_TWEETS_LIMIT, help: 'Safety ceiling; reaching it is a typed failure.' },
        { name: 'page-delay', type: 'int', default: DEFAULT_USER_TWEETS_PAGE_DELAY_SECONDS, help: 'Seconds to wait between cursor pages.' },
    ],
    columns: ['posts', 'receipt'],
    func: async (page, kwargs) => {

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Increase maxPages so the page budget covers posts between now and 'until'.
  2. Narrow 'until' to a recent timestamp and collect incrementally across runs.
  3. Raise USER_TWEETS_PAGE_SIZE if X still honors it, reducing the number of pages required.
  4. Perform an initial full backfill once, then run frequent small incremental collections.
  5. Catch the error and persist oldestSeenAt from the receipt-building path to resume later.

Example fix

// before
const { posts } = await collection({ user: 'handle', until: '2026-01-01', maxPages: 5 });
// after
const { posts } = await collection({ user: 'handle', until: '2026-01-01', maxPages: 200 });
Defensive patterns

Strategy: try-catch

Validate before calling

const expectedPages = Math.ceil(expectedPosts / USER_TWEETS_PAGE_SIZE);
if (expectedPages > maxPages) {
  console.warn(`maxPages ${maxPages} < estimated ${expectedPages} pages needed`);
}

Try / catch

try {
  const { posts } = await collection(...);
} catch (err) {
  if (String(err.message).startsWith('twitter_collection_page_guard_hit')) {
    // resume later using the oldest timestamp reached; raise maxPages for full backfill
  } else throw err;
}

Prevention

When it happens

Trigger: maxPages is smaller than the number of pages needed to walk from the newest post back to 'until' — common for high-volume accounts, old cutoffs, or small page sizes (USER_TWEETS_PAGE_SIZE).

Common situations: First-time deep backfill of a long-running account; 'until' set months back; rate-limit backoff shrinking usable pages; accounts with gaps/deleted tweets inflating page counts.

Related errors


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