jackwener/OpenCLI · error · CommandExecutionError

Browser session required for twitter unbookmark

Error message

Browser session required for twitter unbookmark

What it means

CommandExecutionError (code COMMAND_EXEC) thrown by `twitter unbookmark` because bookmark removal is a browser-write command requiring an interactive page on the logged-in X session. With page null the library fails fast instead of attempting a non-browser path. The message mirrors the sibling unblock/unfollow guards.

Source

Thrown at clis/twitter/unbookmark.js:19

import { CommandExecutionError, TimeoutError } from '@jackwener/opencli/errors';
import { cli, Strategy } from '@jackwener/opencli/registry';
import { parseTweetUrl, buildTwitterArticleScopeSource } from './shared.js';

cli({
    site: 'twitter',
    name: 'unbookmark',
    access: 'write',
    description: 'Remove a tweet from bookmarks',
    domain: 'x.com',
    strategy: Strategy.UI,
    browser: true,
    args: [
        { name: 'url', type: 'string', positional: true, required: true, help: 'Tweet URL to unbookmark' },
    ],
    columns: ['status', 'message'],
    func: async (page, kwargs) => {
        if (!page)
            throw new CommandExecutionError('Browser session required for twitter unbookmark');
        const target = parseTweetUrl(kwargs.url);
        await page.goto(target.url);
        await page.wait({ selector: '[data-testid="primaryColumn"]' });
        const result = await page.evaluate(`(async () => {
        let writeStarted = false;
        try {
            ${buildTwitterArticleScopeSource(target.id)}
            let attempts = 0;
            let removeBtn = null;
            let targetArticle = null;

            while (attempts < 20) {
                targetArticle = findTargetArticle();
                // Check if not bookmarked (already removed)
                const bookmarkBtn = targetArticle?.querySelector('[data-testid="bookmark"]');
                if (bookmarkBtn) {
                    return { ok: true, message: 'Tweet is not bookmarked (already removed).' };
                }

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Connect/start a browser session and log in to x.com, then re-run `twitter unbookmark`
  2. Run the command interactively rather than in API-only/headless mode
  3. In scripts, verify browser session availability before invoking and emit a clear prerequisite error

Example fix

// before
await cli.run(['twitter', 'unbookmark', tweetUrl]); // no browser session
// after
const page = await getBrowserPage('x.com');
if (!page) throw new Error('Start a browser session and log in to x.com first');
await cli.run(['twitter', 'unbookmark', tweetUrl]);
Defensive patterns

Strategy: validation

Validate before calling

if (!browserSession || !browserSession.page) {
  throw new Error('Start a browser session and log in to x.com before running twitter unbookmark');
}

Type guard

function hasBrowserPage(ctx) { return ctx != null && typeof ctx.page === 'object' && ctx.page !== null; }

Try / catch

try {
  await cli.run(['twitter', 'unbookmark', tweetUrl]);
} catch (e) {
  if (e.code === 'COMMAND_EXEC' && /Browser session required/.test(e.message)) {
    console.error('Connect a browser session and log in to x.com first');
  } else throw e;
}

Prevention

When it happens

Trigger: Running `twitter unbookmark <tweet-url>` without an active browser session, so `func` receives page === null/undefined at the guard on line 19.

Common situations: Invoking the CLI headlessly or from scripts without connecting the browser; CI environments with no logged-in Chrome profile; forgetting to log in to x.com before write commands.

Related errors


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