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
- Verify each path exists and is a regular file before invoking: fs.statSync(p).isFile().
- Use absolute paths (or resolve relative paths against the intended cwd) to avoid cwd surprises.
- Fix typos and check case sensitivity of filenames.
- 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
- Use absolute paths or run from a known cwd to avoid resolution surprises
- Check fs.statSync(p).isFile() for each image before posting
- Ensure upstream generation steps completed and files weren't renamed/deleted
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
- 封面文件不存在: ${path.resolve(coverPath)}
- Media file not found: ${resolved}
- Story media file not found: ${resolved}
- twitter collection --until must be an RFC3339 timestamp
- twitter collection --limit must be an integer between 1 and
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/640101d60761b5ea.
Report an issue: GitHub.