jackwener/OpenCLI · error · TimeoutError
twitter reply
Error message
twitter reply
What it means
This is the timeout path of the reply submit: after inserting text and clicking Reply, the submit poller ran for SUBMIT_TIMEOUT_MS (15s) without confirming the reply posted (result.unconfirmed). The command throws a TimeoutError labeled 'twitter reply' with the poller's message and a warning that the reply may already be live, so blind retries risk duplicate replies.
Source
Thrown at clis/twitter/reply.js:291
const downloaded = await downloadRemoteImage(kwargs['image-url']);
localImagePath = downloaded.absPath;
cleanupDir = downloaded.cleanupDir;
}
// Dedicated composer is normally more reliable than the inline
// tweet page reply box, but X occasionally leaves that route on the
// Home timeline behind a loading dialog. openReplyComposer falls
// back to the target tweet's visible Reply action.
const composer = await openReplyComposer(page, kwargs.url);
if (!composer?.ok) {
throw new CommandExecutionError(composer?.message ?? 'Could not open the reply composer.', 'Open the tweet in the browser and check whether the reply box is available.');
}
if (localImagePath) {
await page.wait({ selector: COMPOSER_FILE_INPUT_SELECTOR, timeout: 20 });
await attachComposerImage(page, localImagePath);
}
const result = await submitReply(page, kwargs.text);
if (result.unconfirmed) {
throw new TimeoutError('twitter reply', SUBMIT_TIMEOUT_MS / 1000, `${result.message} Check the tweet before retrying; the reply 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,
...(result.url ? { url: result.url } : {}),
...(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
- Check the tweet (or your profile's Replies tab) before retrying — the reply may already be live and retrying duplicates it.
- Retry the command once; a second attempt usually confirms quickly if the first actually posted.
- Increase SUBMIT_TIMEOUT_MS if your environment is consistently slow (e.g. 30_000).
- Verify the account is not rate-limited or logged out.
Example fix
// before const SUBMIT_TIMEOUT_MS = 15_000; // after const SUBMIT_TIMEOUT_MS = 30_000; // slow networks / delayed X confirmation
Defensive patterns
Strategy: try-catch
Validate before calling
// Ensure non-empty, within-length text before invoking:
if (!text || text.length > 280) throw new Error('Reply text empty or too long'); Type guard
null
Try / catch
try {
await cli('twitter', 'reply', { url, text });
} catch (e) {
if (e.name === 'TimeoutError' && String(e.message).includes('twitter reply')) {
// DO NOT retry immediately: verify the reply didn't post first
const posted = await checkProfileReplies(url);
if (!posted) await cli('twitter', 'reply', { url, text });
} else throw e;
} Prevention
- Check the tweet/profile before any retry — unconfirmed timeouts may have posted.
- Raise SUBMIT_TIMEOUT_MS for slow networks.
- Watch for X rate limits that delay post confirmation.
- Run during stable network conditions; avoid parallel reply jobs on one account.
When it happens
Trigger: submitReply's 15-second polling loop ends without detecting the success state or a status URL — slow network, a stuck compose dialog, an error toast X shows slowly, or the success permalink element not appearing in time.
Common situations: Slow connection or heavy page load pushing confirmation past 15s; X showing a transient error banner ('Something went wrong') that the poller never resolves; rate limiting delaying post creation.
Related errors
- Unexpected 12306 probe: ${JSON.stringify(probe)}
- ${result.message} Check muted words before retrying; the wor
- Waiting for 12306 tk auth cookie
- ChatGPT did not create a conversation URL after sending the
- ChatWise response
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/f6c90d9d0c74899f.
Report an issue: GitHub.