jackwener/OpenCLI · error · ArgumentError
Use either <username> or --tweet-url, not both
Error message
Use either <username> or --tweet-url, not both
What it means
opencli twitter download accepts exactly one targeting mode: a positional <username> for profile-wide media scraping, or --tweet-url for a single tweet. The command deliberately rejects supplying both to avoid ambiguous intent, throwing an ArgumentError (a CliError subclass) before any browser work starts.
Source
Thrown at clis/twitter/download.js:326
strategy: Strategy.COOKIE,
browser: true,
args: [
{ name: 'username', positional: true, help: 'Twitter username (with or without @) to scan their profile media. Either <username> or --tweet-url is required.' },
{ name: 'tweet-url', help: 'Single tweet URL to download. Use this OR <username>, not both required at once.' },
{ name: 'limit', type: 'int', default: 10, help: 'Maximum number of media items to download when scanning a profile (default 10). Ignored when --tweet-url is used.' },
{ name: 'output', default: './twitter-downloads', help: 'Output directory (default ./twitter-downloads). A per-source subdir is created inside.' },
],
columns: ['index', 'tweet_id', 'url', 'type', 'status', 'size'],
func: async (page, kwargs) => {
try {
const rawUsername = String(kwargs.username ?? '').trim();
const tweetUrl = String(kwargs['tweet-url'] ?? '').trim();
const output = kwargs.output;
if (!rawUsername && !tweetUrl) {
throw new ArgumentError('twitter download requires either <username> or --tweet-url');
}
if (rawUsername && tweetUrl) {
throw new ArgumentError('Use either <username> or --tweet-url, not both');
}
if (tweetUrl) {
return downloadSingleTweet(page, tweetUrl, output);
}
const limit = requireLimit(kwargs.limit);
const username = normalizeTwitterScreenName(rawUsername);
if (!username) {
throw new ArgumentError('twitter download username must be a valid Twitter/X handle', 'Example: opencli twitter download @jack --limit 20');
}
return downloadUserMedia(page, username, limit, output);
}
catch (err) {
if (err instanceof CliError) throw err;
throw new CommandExecutionError(`twitter download failed: ${err?.message ?? String(err)}`);
}
},
});
View on GitHub (pinned to 49907e53dc)
Solutions
- Remove the positional <username> and keep only --tweet-url when downloading a single tweet
- Remove --tweet-url and keep only the username when scraping a profile's media
- Fix wrapper scripts/aliases to pass only one of the two values conditionally
Example fix
// before opencli twitter download @jack --tweet-url https://x.com/jack/status/123 // after opencli twitter download --tweet-url https://x.com/jack/status/123
Defensive patterns
Strategy: validation
Validate before calling
if (username && tweetUrl) {
throw new Error('Pass either <username> or --tweet-url, not both');
}
if (!username && !tweetUrl) {
throw new Error('Pass <username> or --tweet-url');
} Prevention
- In scripts, build the argument list conditionally so only one targeting mode is ever appended
- Quote shell variables carefully to avoid accidentally passing empty-looking extra args
When it happens
Trigger: Calling `opencli twitter download @jack --tweet-url https://x.com/user/status/123...` where both the positional username argument and the --tweet-url kwarg are non-empty after trimming.
Common situations: Shell aliases or wrapper scripts that always append a username; copy-pasting an example command that included both; scripting where a variable for tweet-url is set but a default username remains in the command line.
Related errors
- --resume-file requires --all
- twitter download requires either <username> or --tweet-url
- twitter download username must be a valid Twitter/X handle
- --top-by-engagement cannot be combined with --output-file
- --output-file requires --all
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/6646aae34068efc6.
Report an issue: GitHub.