jackwener/OpenCLI · error · CommandExecutionError
Unsupported image format "${ext}". Supported: jpg, png, gif,
Error message
Unsupported image format "${ext}". Supported: jpg, png, gif, webp What it means
CommandExecutionError thrown by validateImagePaths when an image path has an extension outside the supported set (.jpg, .jpeg, .png, .gif, .webp). The extension check runs after path.resolve and lowercase extname comparison, before the file-existence check, so unsupported formats are rejected before any upload attempt. X's composer does not accept arbitrary formats as images.
Source
Thrown at clis/twitter/post.js:28
const UPLOAD_TIMEOUT_MS = 30_000;
const COMPOSER_POLL_MS = 250;
const COMPOSER_TIMEOUT_MS = 10_000;
const SUBMIT_POLL_MS = 500;
const SUBMIT_TIMEOUT_MS = 15_000;
const COMPOSE_URL = 'https://x.com/compose/post';
const FILE_INPUT_SELECTOR = 'input[type="file"][data-testid="fileInput"]';
const SUPPORTED_EXTENSIONS = new Set(['.jpg', '.jpeg', '.png', '.gif', '.webp']);
function validateImagePaths(raw) {
const paths = raw.split(',').map(s => s.trim()).filter(Boolean);
if (paths.length > MAX_IMAGES) {
throw new CommandExecutionError(`Too many images: ${paths.length} (max ${MAX_IMAGES})`);
}
return paths.map(p => {
const absPath = path.resolve(p);
const ext = path.extname(absPath).toLowerCase();
if (!SUPPORTED_EXTENSIONS.has(ext)) {
throw new CommandExecutionError(`Unsupported image format "${ext}". Supported: jpg, png, gif, webp`);
}
const stat = fs.statSync(absPath, { throwIfNoEntry: false });
if (!stat || !stat.isFile()) {
throw new CommandExecutionError(`Not a valid file: ${absPath}`);
}
return absPath;
});
}
function isUnsupportedInsertTextError(err) {
const msg = err instanceof Error ? err.message : String(err);
const lower = msg.toLowerCase();
return lower.includes('unknown action') || lower.includes('not supported') || lower.includes('inserttext returned no inserted flag');
}
function requirePostActionResult(value, context) {
const result = unwrapBrowserResult(value);
if (!result || typeof result !== 'object' || Array.isArray(result) || typeof result.ok !== 'boolean') {View on GitHub (pinned to 49907e53dc)
Solutions
- Convert the image to a supported format (jpg/png/gif/webp), e.g. with ImageMagick: magick input.heic output.jpg.
- Check each path's extension before invoking and filter to the supported set.
- Fix misnamed files whose actual format doesn't match their extension.
- For HEIC specifically, export from Photos as JPEG or enable automatic conversion on transfer.
Example fix
// before
await post({ text, images: 'photo.heic,shot.bmp' });
// after
import { execSync } from 'node:child_process';
execSync('magick photo.heic photo.jpg');
execSync('magick shot.bmp shot.png');
await post({ text, images: 'photo.jpg,shot.png' }); Defensive patterns
Strategy: validation
Validate before calling
const SUPPORTED = new Set(['.jpg', '.jpeg', '.png', '.gif', '.webp']);
const bad = paths.filter(p => !SUPPORTED.has(path.extname(p).toLowerCase()));
if (bad.length) throw new Error(`Unsupported formats: ${bad.join(', ')} — convert to jpg/png/gif/webp first`); Type guard
function hasSupportedExtension(p) {
return ['.jpg', '.jpeg', '.png', '.gif', '.webp']
.includes(path.extname(p).toLowerCase());
} Try / catch
try {
await run(['twitter', 'post', '--images', rawImages]);
} catch (err) {
const m = err.message.match(/Unsupported image format "(.+?)"/);
if (m) console.error(`Convert ${m[1]} files to jpg/png/gif/webp, e.g. magick in.heic out.jpg`);
else throw err;
} Prevention
- Convert HEIC/BMP/TIFF/AVIF images to jpg or png before posting
- Verify real file formats match extensions before passing paths
- Pre-validate extensions in pipelines that batch-produce images
When it happens
Trigger: Passing a comma-separated image list containing e.g. 'photo.bmp', 'img.tiff', 'cat.heic', or 'shot.JPEG.txt' — path.extname resolves to an extension not in SUPPORTED_EXTENSIONS and the error embeds the offending extension.
Common situations: iPhone HEIC photos not yet converted; BMP/TIFF exports from design tools; AVIF files from newer pipelines; misnamed files where the real extension isn't the last one; screenshots saved as .webp on some systems being fine but .pdf/.svg erroneously passed.
Related errors
- Too many images: ${paths.length} (max ${MAX_IMAGES})
- 不支持的视频格式: ${ext}(支持 mp4/mov/avi/webm)
- Failed to read image dimensions for ${filePath}
- twitter collection --until must be an RFC3339 timestamp
- twitter collection --limit must be an integer between 1 and
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/4b8e89311a652119.
Report an issue: GitHub.