jackwener/OpenCLI · error · CliError
FILE_READ_ERROR
FILE_READ_ERROR
Error message
Unable to inspect file: ${resolvedPath} What it means
readPdfFile() calls fs.stat() to inspect the candidate PDF before reading it. If stat() fails for any reason other than ENOENT (which produces the dedicated FILE_NOT_FOUND 'File not found' error), the library wraps it as FILE_READ_ERROR 'Unable to inspect file: <path>'. This means the filesystem could not be queried at all — typically a permissions problem, a broken symlink loop, or a path component that is not a directory.
Source
Thrown at clis/paperreview/utils.js:67
export async function readPdfFile(inputPath) {
const rawPath = trimOrEmpty(inputPath);
if (!rawPath) {
throw new CliError('ARGUMENT', 'A PDF path is required.', 'Provide a local PDF file path');
}
const resolvedPath = path.resolve(rawPath);
const fileName = path.basename(resolvedPath);
if (!fileName.toLowerCase().endsWith('.pdf')) {
throw new CliError('ARGUMENT', 'The input file must end with .pdf.', 'Provide a PDF file path');
}
let fileStat;
try {
fileStat = await fs.stat(resolvedPath);
}
catch (error) {
if (error?.code === 'ENOENT') {
throw new CliError('FILE_NOT_FOUND', `File not found: ${resolvedPath}`, 'Provide a valid PDF file path');
}
throw new CliError('FILE_READ_ERROR', `Unable to inspect file: ${resolvedPath}`, 'Check file permissions and try again');
}
if (!fileStat.isFile()) {
throw new CliError('FILE_NOT_FOUND', `Not a file: ${resolvedPath}`, 'Provide a valid PDF file path');
}
if (fileStat.size < 100) {
throw new CliError('ARGUMENT', 'The PDF is too small. paperreview.ai requires at least 100 bytes.', 'Provide the final paper PDF');
}
if (fileStat.size > MAX_PDF_BYTES) {
throw new CliError('FILE_TOO_LARGE', 'The PDF is larger than paperreview.ai\'s 10MB limit.', 'Compress the PDF or submit a smaller file');
}
let buffer;
try {
buffer = await fs.readFile(resolvedPath);
}
catch {
throw new CliError('FILE_READ_ERROR', `Unable to read file: ${resolvedPath}`, 'Check file permissions and try again');
}
return {View on GitHub (pinned to 49907e53dc)
Solutions
- Check permissions with ls -l on the file and every parent directory; chmod/chown so the running user can access the path
- Verify the path is valid: ensure no path component is a regular file and the path has no symlink loop (namei -l <path>)
- Run stat <path> yourself to reproduce the underlying errno and fix accordingly
- If on a CI runner, confirm the workspace/files were checked out with readable permissions
Example fix
// before
await readPdfFile(process.argv[2]);
// after
import { accessSync, constants } from 'node:fs';
const p = process.argv[2];
accessSync(p, constants.R_OK); // throws a clear EACCES before the CLI call
await readPdfFile(p); Defensive patterns
Strategy: validation
Validate before calling
import fs from 'node:fs';
import path from 'node:path';
function canInspect(p) {
try {
const resolved = path.resolve(p);
fs.accessSync(resolved, fs.constants.R_OK | fs.constants.F_OK);
return true;
} catch (e) {
if (e.code === 'ENOENT') return false; // different error path
return false; // EACCES/ELOOP/ENOTDIR etc. -> would raise FILE_READ_ERROR
}
} Type guard
function isRegularFileStat(s) {
return typeof s === 'object' && s !== null && typeof s.isFile === 'function' && s.isFile();
} Try / catch
try {
const pdf = await readPdfFile(userPath);
} catch (e) {
if (e?.code === 'FILE_READ_ERROR' && e.message.startsWith('Unable to inspect file')) {
console.error(`Cannot access ${userPath}: check permissions and that no parent path component is a file.`);
} else throw e;
} Prevention
- Verify permissions (ls -l on path and parents) before invoking the CLI
- Avoid passing paths under symlink loops or with a file as a parent component
- Run the CLI as a user with access to the paper directory (not root-only locations)
- Use namei -l <path> to trace permission issues along the whole path
When it happens
Trigger: Calling readPdfFile() when fs.stat(resolvedPath) rejects with something other than ENOENT: EACCES (no permission on the file or a parent directory), ELOOP (symlink loop), ENOTDIR (a path component is a file, e.g. /path/to.pdf/sub.pdf), or filesystem I/O errors.
Common situations: Running the CLI as a user lacking read permission on the file or a parent directory; passing a path under a symlink loop; passing a path whose parent component is actually a file; read-protected directories on shared CI runners.
Related errors
- File could not be read: ${path}
- MiniMax music cannot reserve output file ${target}: ${error?
- File not found: ${path}
- File must be a readable text file: ${path}
- Receipt file cannot be read: ${receipt}
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/5fbcca0f76cac160.
Report an issue: GitHub.