jackwener/OpenCLI · error · CliError

FILE_NOT_FOUND

FILE_NOT_FOUND

Error message

File not found: ${resolvedPath}

What it means

readPdfFile calls fs.stat on the resolved path and translates ENOENT into CliError with code FILE_NOT_FOUND and the absolute path in the message. This confirms the extension was valid but no file exists at that location. Other stat errors (e.g. permissions) become FILE_READ_ERROR instead.

Source

Thrown at clis/paperreview/utils.js:65

    return numeric;
}
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');

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Use the absolute path printed in the message to confirm what the CLI looked for; verify the file exists with ls.
  2. cd to the right directory or pass an absolute path.
  3. Re-generate or restore the PDF if it was deleted.
  4. Check symlink targets if the path is a link.

Example fix

// before
cli submit --pdf papre.pdf   # typo
// after
cli submit --pdf /abs/path/paper.pdf
Defensive patterns

Strategy: validation

Validate before calling

import { statSync } from 'node:fs';
try {
  statSync(path.resolve(pdfPath));
} catch (e) {
  if (e.code === 'ENOENT') throw new Error(`PDF does not exist: ${path.resolve(pdfPath)}`);
}

Type guard

function pdfExists(v) {
  try { return statSync(path.resolve(v)).isFile(); } catch { return false; }
}

Try / catch

try {
  await cli.submit({ pdf: pdfPath });
} catch (err) {
  if (err.code === 'FILE_NOT_FOUND') console.error(`No such file: ${err.message}`);
  else if (err.code === 'FILE_READ_ERROR') console.error('Check file permissions');
  else throw err;
}

Prevention

When it happens

Trigger: Passing a well-formed .pdf path that does not exist: typo in the name, file deleted/moved, wrong working directory with a relative path, or a symlink pointing nowhere.

Common situations: Typos in file names; running the CLI from a different cwd than expected in scripts; files on unmounted drives; cleanup jobs removing generated PDFs before submission.

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/1ec75b049c4a08b7. Report an issue: GitHub.