jackwener/OpenCLI · error · CommandExecutionError
Use either --image or --image-url, not both.
Error message
Use either --image or --image-url, not both.
What it means
The reply command accepts an image either as a local path (--image) or as a remote URL (--image-url), but not both at once. Supplying both is ambiguous (which one gets attached?), so the command fails fast with this CommandExecutionError before any navigation or posting.
Source
Thrown at clis/twitter/reply.js:265
site: 'twitter',
name: 'reply',
access: 'write',
description: 'Reply to a specific tweet, optionally with a local or remote image',
domain: 'x.com',
strategy: Strategy.UI, // Uses the UI directly to input and click post
browser: true,
args: [
{ name: 'url', type: 'string', required: true, positional: true, help: 'The URL of the tweet to reply to' },
{ name: 'text', type: 'string', required: true, positional: true, help: 'The text content of your reply' },
{ name: 'image', help: 'Optional local image path to attach to the reply' },
{ name: 'image-url', help: 'Optional remote image URL to download and attach to the reply' },
],
columns: ['status', 'message', 'text', 'url'],
func: async (page, kwargs) => {
if (!page)
throw new CommandExecutionError('Browser session required for twitter reply');
if (kwargs.image && kwargs['image-url']) {
throw new CommandExecutionError('Use either --image or --image-url, not both.');
}
let localImagePath;
let cleanupDir;
try {
if (kwargs.image) {
localImagePath = resolveImagePath(kwargs.image);
} else if (kwargs['image-url']) {
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.');View on GitHub (pinned to 49907e53dc)
Solutions
- Remove one of the two flags — keep --image for local files or --image-url for remote URLs.
- If the remote image is wanted, download it first and pass only --image, or vice versa.
- Check wrapper scripts/config for a default --image-url that collides with a manual --image.
Example fix
// before opencli twitter reply --url <tweet> --text "hi" --image ./pic.png --image-url https://x.com/pic.png // after opencli twitter reply --url <tweet> --text "hi" --image ./pic.png
Defensive patterns
Strategy: validation
Validate before calling
if (opts.image && opts.imageUrl) {
throw new Error('Pass either --image or --image-url, not both');
} Type guard
null
Try / catch
try {
await cli('twitter', 'reply', { url, text, image });
} catch (e) {
if (String(e.message).includes('Use either --image or --image-url')) {
// drop the conflicting flag and retry with one image source
} else throw e;
} Prevention
- Centralize image options in one helper that picks a single source.
- Audit wrapper scripts/config files for a default --image-url that collides with --image.
- Document the exclusivity in your command templates.
When it happens
Trigger: Calling `twitter reply --image ./pic.png --image-url https://example.com/pic.png` — both truthy kwargs trigger the check at clis/twitter/reply.js:265.
Common situations: Script templates where both flags were filled in by defaults; copy-pasting an example command and leaving both image flags; a config file injecting --image-url on top of a manually passed --image.
Related errors
- At least one Twitter/X username is required
- delay-ms must be an integer between 0 and ${MAX_DELAY_MS}
- 12306 tk auth cookie missing
- ${probe.detail}
- 12306 whoami failed: ${probe.detail}
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/83980dcc1dff9351.
Report an issue: GitHub.