jackwener/OpenCLI · error · CommandExecutionError
Browser session required for twitter unfollow
Error message
Browser session required for twitter unfollow
What it means
CommandExecutionError (code COMMAND_EXEC) thrown by `twitter unfollow` because unfollowing is a browser-write command needing an interactive page tied to the logged-in X session. When page is null the guard throws immediately rather than attempting the action. Identical guard pattern to twitter unblock and unbookmark.
Source
Thrown at clis/twitter/unfollow.js:17
import { cli, Strategy } from '@jackwener/opencli/registry';
import { CommandExecutionError, TimeoutError } from '@jackwener/opencli/errors';
cli({
site: 'twitter',
name: 'unfollow',
access: 'write',
description: 'Unfollow a Twitter user',
domain: 'x.com',
strategy: Strategy.UI,
browser: true,
args: [
{ name: 'username', type: 'string', positional: true, required: true, help: 'Twitter screen name (without @)' },
],
columns: ['status', 'message'],
func: async (page, kwargs) => {
if (!page)
throw new CommandExecutionError('Browser session required for twitter unfollow');
const username = kwargs.username.replace(/^@/, '');
await page.goto(`https://x.com/${username}`);
await page.wait({ selector: '[data-testid="primaryColumn"]' });
const result = await page.evaluate(`(async () => {
let writeStarted = false;
try {
let attempts = 0;
let unfollowBtn = null;
while (attempts < 20) {
// Check if already not following
const followBtn = document.querySelector('[data-testid$="-follow"]');
if (followBtn) {
return { ok: true, message: 'Not following @${username} (already unfollowed).' };
}
unfollowBtn = document.querySelector('[data-testid$="-unfollow"]');
if (unfollowBtn) break;View on GitHub (pinned to 49907e53dc)
Solutions
- Start/connect a browser session and log in to x.com, then re-run `twitter unfollow`
- Run the command in interactive mode so a page is passed to the command's func
- In scripts, check browser availability before invoking and fail with a clear prerequisite message
Example fix
// before
await cli.run(['twitter', 'unfollow', 'user']); // 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', 'unfollow', 'user']); 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 unfollow');
} Type guard
function hasBrowserPage(ctx) { return ctx != null && typeof ctx.page === 'object' && ctx.page !== null; } Try / catch
try {
await cli.run(['twitter', 'unfollow', user]);
} 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
- Connect the browser session and log in to x.com before any follow-graph writes
- Run write commands interactively, never in page-less API mode
- Add a browser-session preflight to batch unfollow scripts
- Provision a logged-in Chrome profile for CI if writes are required there
When it happens
Trigger: Running `twitter unfollow <username>` without an active browser session, so `func` receives page === null/undefined at the guard on line 17.
Common situations: Scripted/headless invocation without connecting the browser; CI with no logged-in Chrome; forgetting the x.com login/bootstrap step before write commands.
Related errors
- Browser session required for twitter unblock
- Browser session required for twitter unbookmark
- Browser session required for twitter hide-reply
- Browser session required for twitter like
- Browser session required for zhihu comment
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/ecdc65e1c46bb6f2.
Report an issue: GitHub.