jackwener/OpenCLI · error · CommandExecutionError

Nothing changed. Open the tweet in the browser and retry.

Error message

Nothing changed. Open the tweet in the browser and retry.

What it means

After loading the tweet page and executing buildDeleteScript, the library checks result.ok from the in-page script. If the delete did not succeed (X API call inside the page failed, tweet already gone, permissions issue, UI changed), it throws with the script's message and the hint that nothing was changed, so the user knows the tweet still exists.

Source

Thrown at clis/twitter/delete.js:88

    strategy: Strategy.UI, // Utilizes internal DOM flows for interaction
    browser: true,
    args: [
        { name: 'url', type: 'string', required: true, positional: true, help: 'The URL of the tweet to delete' },
    ],
    columns: ['status', 'message'],
    func: async (page, kwargs) => {
        if (!page)
            throw new CommandExecutionError('Browser session required for twitter delete');
        // parseTweetUrl throws ArgumentError on malformed/off-domain inputs —
        // this replaces the ad-hoc local extractTweetId which only checked
        // the path shape and accepted any host (silent: would try to act on
        // attacker-controlled redirect URLs).
        const target = parseTweetUrl(kwargs.url);
        await page.goto(target.url);
        await page.wait({ selector: '[data-testid="primaryColumn"]' }); // Wait for tweet to load completely
        const result = unwrapBrowserResult(await page.evaluate(buildDeleteScript(target.id)));
        if (!result.ok) {
            throw new CommandExecutionError(result.message, 'Nothing changed. Open the tweet in the browser and retry.');
        }
        await page.wait(2);
        return [{
                status: 'success',
                message: result.message
            }];
    }
});
export const __test__ = {
    buildDeleteScript,
};

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Open the tweet URL in the browser and attempt deletion manually — the message says nothing changed, so retry once the session/permissions are confirmed.
  2. Verify the logged-in account is the tweet's author and the tweet still exists (404s and foreign tweets both fail).
  3. Refresh login/session cookies if the in-page mutation returns unauthorized.
  4. Update the library if X changed its delete mutation protocol (script may target stale endpoints).
  5. If bulk-deleting, add delays between deletions to avoid X rate limits rejecting the mutation.

Example fix

// before
const result = unwrapBrowserResult(await page.evaluate(buildDeleteScript(target.id)));
if (!result.ok) throw new CommandExecutionError(result.message, '...retry.');
// after
const result = unwrapBrowserResult(await page.evaluate(buildDeleteScript(target.id)));
if (!result.ok) {
  if (/already|not found/i.test(result.message)) return [{ status: 'already-deleted', message: result.message }];
  throw new CommandExecutionError(result.message, 'Nothing changed. Open the tweet in the browser and retry.');
}
Defensive patterns

Strategy: try-catch

Validate before calling

// before deleting, confirm the tweet exists and belongs to the session's account
await page.goto(target.url);
await page.wait({ selector: '[data-testid="primaryColumn"]' });
if (await page.evaluate(() => document.body.innerText.includes('This post was deleted'))) {
  return; // already gone
}

Type guard

function isSuccessfulDelete(result) {
  return Boolean(result && result.ok === true && typeof result.message === 'string');
}

Try / catch

try {
  await cliRun('twitter delete', { url });
} catch (err) {
  if (/Nothing changed/.test(err.message)) {
    // verify authorship + existence, refresh session, retry once manually
  } else throw err;
}

Prevention

When it happens

Trigger: page.evaluate's delete script returns ok:false — e.g. the tweet was already deleted, the logged-in account lacks permission (not the author), X's internal mutation endpoint rejected the request (rate limit, CSRF token mismatch), or the DOM/protocol changed so the script failed to complete.

Common situations: Deleting a tweet belonging to a different account; double-running a delete after a prior success; X frontend update changing the delete mutation or its tokens; session cookies stale so the in-page API call returns unauthorized; rate limiting on rapid successive deletions.

Related errors


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