jackwener/OpenCLI · error · CommandExecutionError

twitter_bookmarks_archive_incomplete

twitter_bookmarks_archive_incomplete

Error message

twitter_bookmarks_archive_incomplete: stopped after ${pages} page(s); completion cannot be proven

What it means

Thrown when a full-bookmark archive run (--all) stops paginating without reaching the natural end of the timeline, so the tool cannot prove every bookmark was captured. The library refuses to report an 'archive' result it cannot guarantee complete, and instead surfaces the resume cursor file so the run can be continued.

Source

Thrown at clis/twitter/bookmarks.js:305

            throw new EmptyResultError('twitter bookmarks', 'No bookmarks found for the logged-in account');
        }
        // Resume is only removed after the timeline is truly exhausted. Hitting
        // --max-pages, partial API errors after some rows, or an interrupt must
        // leave the resume file so the next run can continue.
        if (exhausted)
            removeResumeFile(resumeFile);
        if (useOutputFile) {
            return {
                outputFile,
                count: outputCount,
                source: 'bookmarks',
                complete: exhausted,
                pages,
                ...(exhausted ? {} : { cursor, resumeFile: resumeFile || null }),
            };
        }
        if (fetchAll && !exhausted) {
            throw new CommandExecutionError(
                `twitter_bookmarks_archive_incomplete: stopped after ${pages} page(s); completion cannot be proven`,
                resumeFile ? `Resume with --resume-file ${resumeFile}` : 'Rerun with --resume-file to preserve continuation state.',
            );
        }
        const trimmed = fetchAll ? allTweets : allTweets.slice(0, limit);
        return applyTopByEngagement(trimmed, topByEngagement);
    },
});
export const __test__ = {
    parseBookmarks,
    extractBookmarkTweet,
    readResumeFile,
};

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Rerun with --resume-file <path> so pagination state (cursor) is persisted and can continue where the run stopped
  2. Check for rate-limit headers/errors from X and wait before retrying the resume run
  3. Verify the account's bookmark count against the pages fetched to see if truncation is systemic
  4. Reduce per-request pressure (slower page delay, smaller page size) and resume again

Example fix

// before
npx opencli twitter bookmarks --all
// after
npx opencli twitter bookmarks --all --resume-file ./bookmarks-resume.json
# on stop:
npx opencli twitter bookmarks --all --resume-file ./bookmarks-resume.json --resume
Defensive patterns

Strategy: try-catch

Validate before calling

const args = ['twitter','bookmarks','--all'];
if (!args.includes('--resume-file')) {
  const resume = `./bookmarks-resume-${Date.now()}.json`;
  args.push('--resume-file', resume); // preserve cursor so stops are resumable
}

Type guard

function isCompleteArchive(result) {
  return result != null && result.complete === true && typeof result.pages === 'number';
}

Try / catch

try {
  const archive = await runTwitterBookmarks({ all: true, resumeFile });
  if (!archive.complete) throw new Error('incomplete');
} catch (err) {
  if (String(err.message).startsWith('twitter_bookmarks_archive_incomplete')) {
    // rerun with --resume-file <resumeFile> --resume
  } else throw err;
}

Prevention

When it happens

Trigger: fetchAll is true, the X bookmarks endpoint stops returning a cursor / exhausts pages before exhausted=true (rate limiting, API truncation, page cap), and a CommandExecutionError is raised with the page count.

Common situations: Large bookmark collections hitting API page limits or rate limits mid-run; X GraphQL changes that end pagination early; interrupted sessions where the cursor was lost before the resume file was set.

Related errors


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