jackwener/OpenCLI · error · ArgumentError

Unsupported image format "${ext}". Supported: jpg, jpeg, png

Error message

Unsupported image format "${ext}". Supported: jpg, jpeg, png, gif, webp

What it means

resolveImagePath checks the file extension against SUPPORTED_IMAGE_EXTENSIONS (.jpg, .jpeg, .png, .gif, .webp) — the formats the X composer accepts. Files with other extensions throw ArgumentError even if the content is a valid image. The check is extension-based, not content-based (no MIME sniffing).

Source

Thrown at clis/twitter/utils.js:47

    'image/gif': '.gif',
    'image/webp': '.webp',
};

/**
 * Validate a single image path. Throws {@link ArgumentError} on bad input
 * (typed input failure surfaces before any browser interaction).
 *
 * @param {string} imagePath - Local filesystem path, may be relative.
 * @returns {string} Absolute resolved path.
 */
export function resolveImagePath(imagePath) {
    const absPath = path.resolve(imagePath);
    if (!fs.existsSync(absPath)) {
        throw new ArgumentError(`Image file not found: ${absPath}`);
    }
    const ext = path.extname(absPath).toLowerCase();
    if (!SUPPORTED_IMAGE_EXTENSIONS.has(ext)) {
        throw new ArgumentError(`Unsupported image format "${ext}". Supported: jpg, jpeg, png, gif, webp`);
    }
    const stat = fs.statSync(absPath);
    if (stat.size > MAX_IMAGE_SIZE_BYTES) {
        throw new ArgumentError(`Image too large: ${(stat.size / 1024 / 1024).toFixed(1)} MB (max ${MAX_IMAGE_SIZE_BYTES / 1024 / 1024} MB)`);
    }
    return absPath;
}

/**
 * Resolve the file extension to use when persisting a remote image: prefer
 * Content-Type, fall back to URL pathname.
 */
export function resolveImageExtension(url, contentType) {
    const normalizedContentType = (contentType || '').split(';')[0].trim().toLowerCase();
    if (normalizedContentType && CONTENT_TYPE_TO_EXTENSION[normalizedContentType]) {
        return CONTENT_TYPE_TO_EXTENSION[normalizedContentType];
    }
    try {

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Convert the image to a supported format (jpg/png/gif/webp), e.g. `magick input.heic output.jpg` or `sips -s format jpeg input.heic --out output.jpg`.
  2. Rename the file with the correct extension if the content is already a supported format but misnamed (verify with `file image`).
  3. For HEIC, export to JPEG from the Photos app or enable 'Most Compatible' camera format on iOS.

Example fix

// before
await postWithImage('screenshot.bmp');
// after: convert first
import { execSync } from 'node:child_process';
execSync('magick screenshot.bmp screenshot.png');
await postWithImage('screenshot.png');
Defensive patterns

Strategy: validation

Validate before calling

const SUPPORTED = new Set(['.jpg', '.jpeg', '.png', '.gif', '.webp']);
const ext = path.extname(imagePath).toLowerCase();
if (!SUPPORTED.has(ext)) {
  throw new Error(`Convert ${ext || '(no extension)'} to jpg/png/gif/webp first`);
}

Try / catch

try {
  await postWithImage(imagePath);
} catch (err) {
  if (err instanceof ArgumentError && /Unsupported image format/.test(err.message)) {
    const converted = await convertToJpeg(imagePath); // e.g. magick
    return postWithImage(converted);
  }
  throw err;
}

Prevention

When it happens

Trigger: Passing a local file whose extension is not in the allowlist: .bmp, .tiff, .svg, .avif, .heic, or files with no/uppercase-mismatched extensions (case is normalized via toLowerCase, so .PNG is fine but .avif is rejected).

Common situations: iPhone HEIC photos; modern AVIF/WebP-variant downloads; SVG exports from design tools; screenshots saved as .bmp; files saved without any extension.

Related errors


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