{"record":{"id":"bc3c14905b001186","repo":"jackwener/OpenCLI","slug":"image-file-not-found-abspath","errorCode":null,"errorMessage":"Image file not found: ${absPath}","messagePattern":"Image file not found: (.+?)","errorType":"validation","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"clis/twitter/utils.js","lineNumber":43,"sourceCode":"const CONTENT_TYPE_TO_EXTENSION = {\n    'image/jpeg': '.jpg',\n    'image/jpg': '.jpg',\n    'image/png': '.png',\n    'image/gif': '.gif',\n    'image/webp': '.webp',\n};\n\n/**\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();","sourceCodeStart":25,"sourceCodeEnd":61,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/twitter/utils.js#L25-L61","documentation":"resolveImagePath validates a local image path before any browser interaction. It resolves the path to an absolute one and throws ArgumentError when fs.existsSync reports the file does not exist. This fails fast so a bad --image path never reaches the X composer.","triggerScenarios":"Calling resolveImagePath (or the tweet/post command with an image argument) with a path that doesn't exist on disk: typo, wrong working directory for a relative path, file deleted before upload, or case-mismatched filename on case-sensitive filesystems.","commonSituations":"Running the CLI from a different cwd than expected so relative paths like ./cat.png don't resolve; shell quoting issues; passing a URL instead of a local file; macOS-vs-Linux case sensitivity.","solutions":["Verify the path exists: run `ls -l <path>` (or check with fs.existsSync) and fix typos.","Use an absolute path, or run the command from the directory containing the image.","If the image is remote, download it first (or use the remote-image code path) — this function only accepts local files.","On Linux, check filename casing matches exactly."],"exampleFix":"// before\nawait postWithImage('~/Pictures/cat.png'); // ~ not expanded by Node\n// after\nimport os from 'node:os';\nconst p = imagePath.startsWith('~') ? path.join(os.homedir(), imagePath.slice(1)) : imagePath;\nawait postWithImage(p);","handlingStrategy":"validation","validationCode":"import fs from 'node:fs';\nimport path from 'node:path';\nconst abs = path.resolve(imagePath);\nif (!fs.existsSync(abs) || !fs.statSync(abs).isFile()) {\n  throw new Error(`Image does not exist: ${abs}`);\n}","typeGuard":"function isExistingFile(p) {\n  try { return fs.statSync(p).isFile(); } catch { return false; }\n}","tryCatchPattern":"try {\n  await postWithImage(imagePath);\n} catch (err) {\n  if (err instanceof ArgumentError && err.message.startsWith('Image file not found')) {\n    console.error(`Check the --image path (cwd=${process.cwd()}): ${err.message}`);\n    process.exitCode = 2;\n    return;\n  }\n  throw err;\n}","preventionTips":["Always pass absolute paths; expand '~' manually since Node does not.","Check fs.existsSync before invoking the API, especially in scripts with changing cwd.","Quote paths in the shell to avoid splitting on spaces."],"tags":["filesystem","input-validation","arguments"],"backgroundTag":"file-not-found","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}