jackwener/OpenCLI · error · TimeoutError

twitter quote

Error message

twitter quote

What it means

TimeoutError('twitter quote', ...) thrown when submitQuote finished with result.unconfirmed — the quote tweet could not be confirmed as posted within SUBMIT_TIMEOUT_MS. Because the request may have actually gone through, the error message instructs the user to check their profile before retrying to avoid duplicate quotes.

Source

Thrown at clis/twitter/quote.js:160

                cleanupDir = downloaded.cleanupDir;
            }

            // Dedicated composer is more reliable than the inline quote-tweet button.
            await page.goto(`https://x.com/compose/post?url=${encodeURIComponent(target.url)}`, { waitUntil: 'load', settleMs: 2500 });
            await page.wait({ selector: '[data-testid="tweetTextarea_0"]', timeout: 15 });

            if (localImagePath) {
                await page.wait({ selector: COMPOSER_FILE_INPUT_SELECTOR, timeout: 20 });
                await attachComposerImage(page, localImagePath);
            }

            const result = await submitQuote(page, kwargs.text, target.id);
            if (result.ok) {
                // Wait for network submission to complete
                await page.wait(3);
            }
            if (result.unconfirmed) {
                throw new TimeoutError('twitter quote', SUBMIT_TIMEOUT_MS / 1000, `${result.message} Check your profile before retrying; the quote may already be live.`);
            }
            if (!result.ok) {
                throw new CommandExecutionError(result.message, 'Nothing was posted. Open the tweet in the browser and retry.');
            }
            return [{
                    status: 'success',
                    message: result.message,
                    text: kwargs.text,
                    ...(kwargs.image ? { image: kwargs.image } : {}),
                    ...(kwargs['image-url'] ? { 'image-url': kwargs['image-url'] } : {}),
                }];
        } finally {
            if (cleanupDir) {
                fs.rmSync(cleanupDir, { recursive: true, force: true });
            }
        }
    }
});

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Check your x.com profile to see whether the quote actually posted before retrying (avoid duplicates)
  2. Increase SUBMIT_TIMEOUT_MS if submissions are consistently slow
  3. Re-run after confirming the quote is absent; if present, skip retrying
  4. Update the library if x.com changed the confirmation signal (toast/URL pattern) that detection relies on
Defensive patterns

Strategy: try-catch

Type guard

function isTimeoutError(e) {
  return e instanceof TimeoutError || e.name === 'TimeoutError';
}

Try / catch

try {
  await cli.run('twitter quote', kwargs);
} catch (e) {
  if (e instanceof TimeoutError) {
    // do NOT auto-retry: the quote may already be live; verify first
    const posted = await checkProfileForQuote(tweetText);
    if (!posted) return cli.run('twitter quote', kwargs);
    return; // already posted
  }
  throw e;
}

Prevention

When it happens

Trigger: The quote submit flow (clicking the post button / awaiting confirmation) did not yield a verifiable success within SUBMIT_TIMEOUT_MS seconds — slow network, x.com UI change, or the confirmation signal (new tweet URL) never appeared.

Common situations: Slow or flaky connection during submission; x.com DOM/network response changes breaking confirmation detection; rate-limiting delaying the post; long-running batch scripts hitting the timeout at scale.

Related errors


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