jackwener/OpenCLI · error · ArgumentError

Image file not found: ${absPath}

Error message

Image file not found: ${absPath}

What it means

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.

Source

Thrown at clis/twitter/utils.js:43

const CONTENT_TYPE_TO_EXTENSION = {
    'image/jpeg': '.jpg',
    'image/jpg': '.jpg',
    'image/png': '.png',
    'image/gif': '.gif',
    'image/webp': '.webp',
};

/**
 * Validate a single image path. Throws {@link ArgumentError} on bad input
 * (typed input failure surfaces before any browser interaction).
 *
 * @param {string} imagePath - Local filesystem path, may be relative.
 * @returns {string} Absolute resolved path.
 */
export function resolveImagePath(imagePath) {
    const absPath = path.resolve(imagePath);
    if (!fs.existsSync(absPath)) {
        throw new ArgumentError(`Image file not found: ${absPath}`);
    }
    const ext = path.extname(absPath).toLowerCase();
    if (!SUPPORTED_IMAGE_EXTENSIONS.has(ext)) {
        throw new ArgumentError(`Unsupported image format "${ext}". Supported: jpg, jpeg, png, gif, webp`);
    }
    const stat = fs.statSync(absPath);
    if (stat.size > MAX_IMAGE_SIZE_BYTES) {
        throw new ArgumentError(`Image too large: ${(stat.size / 1024 / 1024).toFixed(1)} MB (max ${MAX_IMAGE_SIZE_BYTES / 1024 / 1024} MB)`);
    }
    return absPath;
}

/**
 * Resolve the file extension to use when persisting a remote image: prefer
 * Content-Type, fall back to URL pathname.
 */
export function resolveImageExtension(url, contentType) {
    const normalizedContentType = (contentType || '').split(';')[0].trim().toLowerCase();

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Verify the path exists: run `ls -l <path>` (or check with fs.existsSync) and fix typos.
  2. Use an absolute path, or run the command from the directory containing the image.
  3. If the image is remote, download it first (or use the remote-image code path) — this function only accepts local files.
  4. On Linux, check filename casing matches exactly.

Example fix

// before
await postWithImage('~/Pictures/cat.png'); // ~ not expanded by Node
// after
import os from 'node:os';
const p = imagePath.startsWith('~') ? path.join(os.homedir(), imagePath.slice(1)) : imagePath;
await postWithImage(p);
Defensive patterns

Strategy: validation

Validate before calling

import fs from 'node:fs';
import path from 'node:path';
const abs = path.resolve(imagePath);
if (!fs.existsSync(abs) || !fs.statSync(abs).isFile()) {
  throw new Error(`Image does not exist: ${abs}`);
}

Type guard

function isExistingFile(p) {
  try { return fs.statSync(p).isFile(); } catch { return false; }
}

Try / catch

try {
  await postWithImage(imagePath);
} catch (err) {
  if (err instanceof ArgumentError && err.message.startsWith('Image file not found')) {
    console.error(`Check the --image path (cwd=${process.cwd()}): ${err.message}`);
    process.exitCode = 2;
    return;
  }
  throw err;
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Understand the failure class

Background: "File not found" and ENOENT errors: why libraries can't find a file that should exist — this error's family across 50 libraries.

Related errors


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