{"record":{"id":"3c729a706aee0ada","repo":"jackwener/OpenCLI","slug":"unsupported-remote-image-format-normalizedconte","errorCode":null,"errorMessage":"Unsupported remote image format \"${normalizedContentType || 'unknown'}\". Supported: jpg, jpeg, png, gif, webp","messagePattern":"Unsupported remote image format \"(.+?)\"\\. Supported: jpg, jpeg, png, gif, webp","errorType":"validation","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"clis/twitter/utils.js","lineNumber":73,"sourceCode":"\n/**\n * Resolve the file extension to use when persisting a remote image: prefer\n * Content-Type, fall back to URL pathname.\n */\nexport function resolveImageExtension(url, contentType) {\n    const normalizedContentType = (contentType || '').split(';')[0].trim().toLowerCase();\n    if (normalizedContentType && CONTENT_TYPE_TO_EXTENSION[normalizedContentType]) {\n        return CONTENT_TYPE_TO_EXTENSION[normalizedContentType];\n    }\n    try {\n        const pathname = new URL(url).pathname;\n        const ext = path.extname(pathname).toLowerCase();\n        if (SUPPORTED_IMAGE_EXTENSIONS.has(ext))\n            return ext;\n    } catch {\n        // Fall through to the final error below.\n    }\n    throw new ArgumentError(\n        `Unsupported remote image format \"${normalizedContentType || 'unknown'}\". Supported: jpg, jpeg, png, gif, webp`,\n    );\n}\n\n/**\n * Download a remote image to a per-call tmp directory. Returns the absolute\n * path on success. Caller owns the tmp dir and must clean it up. Throws\n * {@link ArgumentError} on bad input or download failure.\n *\n * @returns {Promise<{ absPath: string, cleanupDir: string }>}\n */\nexport async function downloadRemoteImage(imageUrl) {\n    let parsed;\n    try {\n        parsed = new URL(imageUrl);\n    } catch {\n        throw new ArgumentError(`Invalid image URL: ${imageUrl}`);\n    }","sourceCodeStart":55,"sourceCodeEnd":91,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/twitter/utils.js#L55-L91","documentation":"resolveImageExtension determines the file extension for a downloaded remote image from its Content-Type header, falling back to the URL pathname extension. If neither maps to a supported type (jpg/jpeg/png/gif/webp) it throws ArgumentError. This ensures the file saved for the composer upload has an extension X accepts.","triggerScenarios":"Downloading a remote image whose Content-Type is not a supported image type — e.g. text/html (an error/redirect page), application/octet-stream, image/avif, image/heic, or a missing content-type with a URL lacking a recognized extension.","commonSituations":"URL actually returns an HTML login/error page instead of an image; CDN serving AVIF via content negotiation; image hosts returning octet-stream with extensionless URLs; signed URLs whose path has no extension.","solutions":["Use a direct image URL (verify with `curl -sI <url>` that content-type is image/jpeg|png|gif|webp).","Request a non-AVIF variant: add Accept: image/jpeg or use the original file URL many CDNs expose (e.g. strip format params).","Convert the image locally first (download, `magick` convert to png/jpg) and pass a local path instead.","If content-type is HTML, fix the underlying URL — it's probably a login wall or 404 page."],"exampleFix":"// before\nawait postWithImageFromUrl('https://cdn.example.com/i/abc?fmt=avif'); // image/avif\n// after\nconst res = await fetch('https://cdn.example.com/i/abc?fmt=jpg');\n// confirm content-type is image/jpeg before calling","handlingStrategy":"validation","validationCode":"const head = await fetch(imageUrl, { method: 'HEAD' });\nconst type = head.headers.get('content-type') || '';\nif (!/^image\\/(jpeg|png|gif|webp)$/.test(type)) {\n  throw new Error(`URL serves \"${type}\", need jpeg/png/gif/webp: ${imageUrl}`);\n}","typeGuard":null,"tryCatchPattern":"try {\n  await postWithImageFromUrl(imageUrl);\n} catch (err) {\n  if (err instanceof ArgumentError && /Unsupported remote image format/.test(err.message)) {\n    const local = await downloadAndConvertToPng(imageUrl);\n    return postWithImage(local);\n  }\n  throw err;\n}","preventionTips":["Use direct image URLs; check content-type with `curl -sI` first.","Avoid URLs negotiated to image/avif; request jpg/png variants explicitly.","If content-type is text/html, the URL is a login/error page — fix the source URL."],"tags":["content-type","input-validation","http","file-format"],"backgroundTag":"unsupported-content-type","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}