jackwener/OpenCLI · error · ArgumentError

Unsupported media format: ${ext}

Error message

Unsupported media format: ${ext}

What it means

After confirming the media file exists, validateMixedMediaItems checks its lowercase extension against SUPPORTED_IMAGE_EXTENSIONS (.jpg/.jpeg/.png/.webp) and SUPPORTED_VIDEO_EXTENSIONS (.mp4). Any other extension throws ArgumentError with the offending extension and a hint listing supported formats. Extension, not MIME type, is the sole discriminator.

Source

Thrown at clis/instagram/post.js:109

    if (inputs.length > MAX_MEDIA_ITEMS) {
        throw new ArgumentError(`Too many media items: ${inputs.length}`, `Instagram carousel posts support at most ${MAX_MEDIA_ITEMS} items`);
    }
    const items = inputs.map((input) => {
        const resolved = path.resolve(String(input || '').trim());
        if (!resolved) {
            throw new ArgumentError('Media path cannot be empty');
        }
        if (!fs.existsSync(resolved)) {
            throw new ArgumentError(`Media file not found: ${resolved}`);
        }
        const ext = path.extname(resolved).toLowerCase();
        if (SUPPORTED_IMAGE_EXTENSIONS.has(ext)) {
            return { type: 'image', filePath: resolved };
        }
        if (SUPPORTED_VIDEO_EXTENSIONS.has(ext)) {
            return { type: 'video', filePath: resolved };
        }
        throw new ArgumentError(`Unsupported media format: ${ext}`, 'Supported formats: images (.jpg, .jpeg, .png, .webp) and videos (.mp4)');
    });
    return items;
}
function normalizePostMediaItems(kwargs) {
    const media = String(kwargs.media ?? '').trim();
    return validateMixedMediaItems(media.split(',').map((part) => part.trim()).filter(Boolean));
}
function validateInstagramPostArgs(kwargs) {
    const media = kwargs.media;
    if (media === undefined) {
        throw new ArgumentError('Argument "media" is required.', 'Provide --media /path/to/file.jpg or --media /path/a.jpg,/path/b.mp4');
    }
}
function isSafePrivateRouteFallbackError(error) {
    if (!(error instanceof CommandExecutionError))
        return false;
    return error.message.startsWith('Instagram private publish')
        || error.message.startsWith('Instagram private route');

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Convert the file: images to .jpg/.png/.webp, videos to .mp4 (e.g. ffmpeg -i clip.mov clip.mp4)
  2. Rename the file so its extension matches its true format if it is actually supported
  3. For HEIC use sips -s format jpeg photo.heic --out photo.jpg (macOS) or ImageMagick convert
  4. Do not try .gif; Instagram carousels via this CLI do not accept it

Example fix

// before
--media /photos/clip.mov
// after (shell)
ffmpeg -i /photos/clip.mov -c:v libx264 /photos/clip.mp4
--media /photos/clip.mp4
Defensive patterns

Strategy: validation

Validate before calling

const SUPPORTED = new Set(['.jpg', '.jpeg', '.png', '.webp', '.mp4']);
function assertSupportedMedia(media) {
  for (const p of String(media).split(',').map(s => s.trim()).filter(Boolean)) {
    const ext = path.extname(p).toLowerCase();
    if (!SUPPORTED.has(ext)) throw new Error(`Unsupported media format: ${ext} (${p})`);
  }
}
assertSupportedMedia(media);

Type guard

function hasSupportedExtension(p) {
  return ['.jpg','.jpeg','.png','.webp','.mp4'].includes(path.extname(p).toLowerCase());
}

Try / catch

try {
  await cli.post({ media });
} catch (e) {
  if (e instanceof ArgumentError && e.message.startsWith('Unsupported media format')) {
    console.error('Convert to jpg/png/webp/mp4 first. Details:', e.message);
  } else throw e;
}

Prevention

When it happens

Trigger: Passing --media with a file whose extension is .gif, .mov, .avi, .heic, .bmp, or a file with no extension at all — even if the actual content is a supported image/video.

Common situations: iPhone HEIC photos; screen recordings saved as .mov; GIFs users expect Instagram to accept; renamed files that lost their extension; double extensions like photo.jpg.txt.

Related errors


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