jackwener/OpenCLI · error · CommandExecutionError
Gmail thread pagination page ${pageNumber} repeated an earli
Error message
Gmail thread pagination page ${pageNumber} repeated an earlier response; refusing partial results What it means
During pagination, if a page after the first adds zero new thread IDs (all rows were already seen), the library assumes the UI stopped advancing pages and throws CommandExecutionError rather than returning silently truncated results. It protects callers from partial data disguised as a complete result.
Source
Thrown at clis/gmail/utils.js:537
if (clicked !== true) break;
}
}
const bodies = await waitGmailCaptures(
page,
'bv',
pageNumber === 1 ? 'thread list' : `thread pagination page ${pageNumber}`,
);
const pageRows = bodies.flatMap(parseBatchView);
let added = 0;
for (const row of pageRows) {
if (seen.has(row.threadId)) continue;
seen.add(row.threadId);
rows.push(row);
added += 1;
if (rows.length >= limit) return rows;
}
if (pageNumber > 1 && added === 0) {
throw new CommandExecutionError(`Gmail thread pagination page ${pageNumber} repeated an earlier response; refusing partial results`);
}
if (pageRows.length < PAGE_SIZE) break;
}
if (rows.length === 0) {
throw new EmptyResultError('gmail search', `No threads matched "${normalizedQuery}"`);
}
return rows.slice(0, limit);
}
export async function listLabels(page, account = 0) {
await ensureGmailReady(page, account, 'labels');
await installGmailCapture(page, account, 'bv', 'labels');
await submitSearch(page, 'in:anywhere', 'labels');
const bodies = await waitGmailCaptures(page, 'bv', 'labels');
const labels = bodies.flatMap(parseLabels);
const fallback = labels.length === 0 ? await renderedLabels(page, account) : [];
const unique = [...new Map([...labels, ...fallback].map((row) => [row.id, row])).values()];
if (unique.length === 0) throw new EmptyResultError('gmail labels', 'Gmail returned no labels');View on GitHub (pinned to 49907e53dc)
Solutions
- Lower the limit so it fits within one page (PAGE_SIZE) of results
- Retry the search once — the failure is often transient UI state
- If persistent, the query may genuinely have fewer unique results than requested; reduce expectations or refine the query
- Verify the library/browser setup matches a supported Gmail UI version
Example fix
// before
const rows = await queryThreads(page, 'label:unread', { limit: 200 });
// after
const rows = await queryThreads(page, 'label:unread', { limit: 50 }); // fit within one page or retry on CommandExecutionError Defensive patterns
Strategy: retry
Validate before calling
const SAFE_LIMIT = 50; // one page const limit = Math.min(requestedLimit, SAFE_LIMIT);
Type guard
const fitsOnePage = (n) => Number.isInteger(n) && n > 0 && n <= 50;
Try / catch
try { rows = await queryThreads(page, q, { limit }); }
catch (e) { if (e instanceof CommandExecutionError && /repeated an earlier response/.test(e.message)) rows = await queryThreads(page, q, { limit: 50 }); else throw e; } Prevention
- Keep limits within one page size when possible
- Retry once on this specific CommandExecutionError
- Refine queries to reduce reliance on deep pagination
When it happens
Trigger: Querying with a limit larger than one PAGE_SIZE when Gmail's next-page navigation fails or re-renders the same results; repeated thread IDs across pages due to a stale page state or a flaky capture of the results list.
Common situations: Large limit values (limit >> PAGE_SIZE) on slow connections; Gmail UI changes breaking the pagination selector so every 'page' shows the same rows; very small result sets interacting with page-advance logic.
Related errors
- Gmail thread navigation failed
- limit must be a positive integer (1-${max})
- limit must be <= ${max}
- NO_DATA
- ${label} must be a positive integer
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/4dde9ccd1fef5315.
Report an issue: GitHub.