jackwener/OpenCLI · error · CommandExecutionError

Not a valid file: ${absPath}

Error message

Not a valid file: ${absPath}

What it means

CommandExecutionError thrown by validateImagePaths when an image path passes the extension check but fs.statSync(absPath, { throwIfNoEntry: false }) returns undefined or a non-file — i.e. the path does not exist, is a directory, or is otherwise not a regular file. throwIfNoEntry prevents statSync itself from throwing so the CLI can produce a clear per-path error naming the resolved absolute path.

Source

Thrown at clis/twitter/post.js:32

const SUBMIT_TIMEOUT_MS = 15_000;
const COMPOSE_URL = 'https://x.com/compose/post';
const FILE_INPUT_SELECTOR = 'input[type="file"][data-testid="fileInput"]';
const SUPPORTED_EXTENSIONS = new Set(['.jpg', '.jpeg', '.png', '.gif', '.webp']);

function validateImagePaths(raw) {
    const paths = raw.split(',').map(s => s.trim()).filter(Boolean);
    if (paths.length > MAX_IMAGES) {
        throw new CommandExecutionError(`Too many images: ${paths.length} (max ${MAX_IMAGES})`);
    }
    return paths.map(p => {
        const absPath = path.resolve(p);
        const ext = path.extname(absPath).toLowerCase();
        if (!SUPPORTED_EXTENSIONS.has(ext)) {
            throw new CommandExecutionError(`Unsupported image format "${ext}". Supported: jpg, png, gif, webp`);
        }
        const stat = fs.statSync(absPath, { throwIfNoEntry: false });
        if (!stat || !stat.isFile()) {
            throw new CommandExecutionError(`Not a valid file: ${absPath}`);
        }
        return absPath;
    });
}

function isUnsupportedInsertTextError(err) {
    const msg = err instanceof Error ? err.message : String(err);
    const lower = msg.toLowerCase();
    return lower.includes('unknown action') || lower.includes('not supported') || lower.includes('inserttext returned no inserted flag');
}

function requirePostActionResult(value, context) {
    const result = unwrapBrowserResult(value);
    if (!result || typeof result !== 'object' || Array.isArray(result) || typeof result.ok !== 'boolean') {
        throw new CommandExecutionError(`${context} returned a malformed result.`);
    }
    if (Object.prototype.hasOwnProperty.call(result, 'message') && result.message != null && typeof result.message !== 'string') {
        throw new CommandExecutionError(`${context} returned a malformed message.`);

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Verify each path exists and is a regular file before invoking: fs.statSync(p).isFile().
  2. Use absolute paths (or resolve relative paths against the intended cwd) to avoid cwd surprises.
  3. Fix typos and check case sensitivity of filenames.
  4. Ensure upstream steps that generate the images completed before running the post command.

Example fix

// before
const images = 'shot.png,shot.png.bak'.split(',');
await post({ text, images: images.join(',') });
// after
import * as fs from 'node:fs';
import * as path from 'node:path';
const images = ['shot.png', 'shot2.png']
  .map(p => path.resolve(p))
  .filter(p => { try { return fs.statSync(p).isFile(); } catch { return false; } });
await post({ text, images: images.join(',') });
Defensive patterns

Strategy: validation

Validate before calling

import * as fs from 'node:fs';
const missing = paths.filter(p => { try { return !fs.statSync(p).isFile(); } catch { return true; } });
if (missing.length) throw new Error(`Not valid files: ${missing.join(', ')}`);

Type guard

function isExistingFile(p) {
  try { return fs.statSync(p, { throwIfNoEntry: false })?.isFile() === true; }
  catch { return false; }
}

Try / catch

try {
  await run(['twitter', 'post', '--images', rawImages]);
} catch (err) {
  const m = err.message.match(/Not a valid file: (.+)/);
  if (m) console.error(`Check path exists and is a file: ${m[1]} (cwd: ${process.cwd()})`);
  else throw err;
}

Prevention

When it happens

Trigger: Passing a path whose file is missing (deleted/renamed since composing the list), a directory instead of a file, a broken symlink, or a relative path resolved against an unexpected current working directory so path.resolve points somewhere the file isn't.

Common situations: Running the command from a different cwd than expected, making relative paths resolve incorrectly; typos in filenames; CI artifacts not yet generated when the command runs; macOS/Linux path-case mismatches; stale file lists from earlier processing steps.

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/640101d60761b5ea. Report an issue: GitHub.