{"record":{"id":"4b8e89311a652119","repo":"jackwener/OpenCLI","slug":"unsupported-image-format-ext-supported-jpg","errorCode":null,"errorMessage":"Unsupported image format \"${ext}\". Supported: jpg, png, gif, webp","messagePattern":"Unsupported image format \"(.+?)\"\\. Supported: jpg, png, gif, webp","errorType":"validation","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/twitter/post.js","lineNumber":28,"sourceCode":"const UPLOAD_TIMEOUT_MS = 30_000;\nconst COMPOSER_POLL_MS = 250;\nconst COMPOSER_TIMEOUT_MS = 10_000;\nconst SUBMIT_POLL_MS = 500;\nconst SUBMIT_TIMEOUT_MS = 15_000;\nconst COMPOSE_URL = 'https://x.com/compose/post';\nconst FILE_INPUT_SELECTOR = 'input[type=\"file\"][data-testid=\"fileInput\"]';\nconst SUPPORTED_EXTENSIONS = new Set(['.jpg', '.jpeg', '.png', '.gif', '.webp']);\n\nfunction validateImagePaths(raw) {\n    const paths = raw.split(',').map(s => s.trim()).filter(Boolean);\n    if (paths.length > MAX_IMAGES) {\n        throw new CommandExecutionError(`Too many images: ${paths.length} (max ${MAX_IMAGES})`);\n    }\n    return paths.map(p => {\n        const absPath = path.resolve(p);\n        const ext = path.extname(absPath).toLowerCase();\n        if (!SUPPORTED_EXTENSIONS.has(ext)) {\n            throw new CommandExecutionError(`Unsupported image format \"${ext}\". Supported: jpg, png, gif, webp`);\n        }\n        const stat = fs.statSync(absPath, { throwIfNoEntry: false });\n        if (!stat || !stat.isFile()) {\n            throw new CommandExecutionError(`Not a valid file: ${absPath}`);\n        }\n        return absPath;\n    });\n}\n\nfunction isUnsupportedInsertTextError(err) {\n    const msg = err instanceof Error ? err.message : String(err);\n    const lower = msg.toLowerCase();\n    return lower.includes('unknown action') || lower.includes('not supported') || lower.includes('inserttext returned no inserted flag');\n}\n\nfunction requirePostActionResult(value, context) {\n    const result = unwrapBrowserResult(value);\n    if (!result || typeof result !== 'object' || Array.isArray(result) || typeof result.ok !== 'boolean') {","sourceCodeStart":10,"sourceCodeEnd":46,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/twitter/post.js#L10-L46","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nawait post({ text, images: 'photo.heic,shot.bmp' });\n// after\nimport { execSync } from 'node:child_process';\nexecSync('magick photo.heic photo.jpg');\nexecSync('magick shot.bmp shot.png');\nawait post({ text, images: 'photo.jpg,shot.png' });","handlingStrategy":"validation","validationCode":"const SUPPORTED = new Set(['.jpg', '.jpeg', '.png', '.gif', '.webp']);\nconst bad = paths.filter(p => !SUPPORTED.has(path.extname(p).toLowerCase()));\nif (bad.length) throw new Error(`Unsupported formats: ${bad.join(', ')} — convert to jpg/png/gif/webp first`);","typeGuard":"function hasSupportedExtension(p) {\n  return ['.jpg', '.jpeg', '.png', '.gif', '.webp']\n    .includes(path.extname(p).toLowerCase());\n}","tryCatchPattern":"try {\n  await run(['twitter', 'post', '--images', rawImages]);\n} catch (err) {\n  const m = err.message.match(/Unsupported image format \"(.+?)\"/);\n  if (m) console.error(`Convert ${m[1]} files to jpg/png/gif/webp, e.g. magick in.heic out.jpg`);\n  else throw err;\n}","preventionTips":["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"],"tags":["validation","twitter","file-format","image-upload"],"backgroundTag":"unsupported-file-format","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}