{"record":{"id":"4f0a552fa9a633f0","repo":"jackwener/OpenCLI","slug":"image-too-large-stat-size-1024-1024-tofix","errorCode":null,"errorMessage":"Image too large: ${(stat.size / 1024 / 1024).toFixed(1)} MB (max ${MAX_IMAGE_SIZE_BYTES / 1024 / 1024} MB)","messagePattern":"Image too large: (.+?) MB \\(max (.+?) MB\\)","errorType":"validation","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"clis/twitter/utils.js","lineNumber":51,"sourceCode":"/**\n * Validate a single image path. Throws {@link ArgumentError} on bad input\n * (typed input failure surfaces before any browser interaction).\n *\n * @param {string} imagePath - Local filesystem path, may be relative.\n * @returns {string} Absolute resolved path.\n */\nexport function resolveImagePath(imagePath) {\n    const absPath = path.resolve(imagePath);\n    if (!fs.existsSync(absPath)) {\n        throw new ArgumentError(`Image file not found: ${absPath}`);\n    }\n    const ext = path.extname(absPath).toLowerCase();\n    if (!SUPPORTED_IMAGE_EXTENSIONS.has(ext)) {\n        throw new ArgumentError(`Unsupported image format \"${ext}\". Supported: jpg, jpeg, png, gif, webp`);\n    }\n    const stat = fs.statSync(absPath);\n    if (stat.size > MAX_IMAGE_SIZE_BYTES) {\n        throw new ArgumentError(`Image too large: ${(stat.size / 1024 / 1024).toFixed(1)} MB (max ${MAX_IMAGE_SIZE_BYTES / 1024 / 1024} MB)`);\n    }\n    return absPath;\n}\n\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;","sourceCodeStart":33,"sourceCodeEnd":69,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/twitter/utils.js#L33-L69","documentation":"resolveImagePath enforces MAX_IMAGE_SIZE_BYTES = 20MB (a safety net above Twitter's own ~5MB image / 15MB GIF limits). If fs.statSync reports a larger file it throws ArgumentError with the size in MB. Oversized media would fail later at X's upload endpoint, so it is rejected up front.","triggerScenarios":"Passing a local image larger than 20MB: high-resolution PNG screenshots, long GIFs, uncompressed camera RAW-renamed files, or any stat.size exceeding 20*1024*1024 bytes.","commonSituations":"4K/full-page screenshots saved as PNG (often >20MB); long animated GIFs; video files accidentally renamed to .gif; image downloads that were never compressed.","solutions":["Compress or resize the image before uploading, e.g. `magick input.png -resize 1600x -quality 85 output.jpg`.","Convert PNG screenshots to JPEG to shrink them dramatically.","For GIFs, reduce frames/dimensions (`gifsicle --resize-width 800 --colors 128`) or convert to MP4 if the post allows video.","If you legitimately need >20MB media, that cap is a library constant (MAX_IMAGE_SIZE_BYTES in clis/twitter/utils.js:21) — raise it only knowing X's own limits will still apply."],"exampleFix":"// before\nawait postWithImage('fullpage.png'); // 34 MB\n// after\nexecSync('magick fullpage.png -resize 2000x -quality 85 fullpage.jpg'); // ~2 MB\nawait postWithImage('fullpage.jpg');","handlingStrategy":"validation","validationCode":"const MAX = 20 * 1024 * 1024;\nconst stat = fs.statSync(imagePath);\nif (stat.size > MAX) {\n  throw new Error(`${imagePath} is ${(stat.size / 1048576).toFixed(1)} MB; compress below 20 MB first`);\n}","typeGuard":null,"tryCatchPattern":"try {\n  await postWithImage(imagePath);\n} catch (err) {\n  if (err instanceof ArgumentError && /Image too large/.test(err.message)) {\n    const small = await compressImage(imagePath); // magick -resize/-quality\n    return postWithImage(small);\n  }\n  throw err;\n}","preventionTips":["Check file size before upload: keep images < ~5MB and GIFs < 15MB to also satisfy X limits.","Convert large PNG screenshots to JPEG with quality ~85.","Downscale to at most ~1600-2000px on the long edge for typical posts."],"tags":["file-size","input-validation","upload-limits"],"backgroundTag":"payload-too-large","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}