garrytan/gstack · error · Error

input file not found: ${input}

Error message

input file not found: ${input}

What it means

Thrown by generate() (the full PDF pipeline) when the resolved input markdown file does not exist. The input is resolved to an absolute path first, so the message shows the full path that was checked. This is an early validation guard before any rendering work begins.

Source

Thrown at make-pdf/src/orchestrator.ts:84

    const total = ((Date.now() - this.totalStart) / 1000).toFixed(1);
    process.stderr.write(`\r\x1b[KDone in ${total}s. ${extra}\n`);
  }
  fail(stage: string, err: Error): void {
    if (!this.quiet) process.stderr.write("\r\x1b[K");
    // Always emit failure info, even in quiet mode — this is an error path.
    process.stderr.write(`${stage} failed: ${err.message}\n`);
  }
}

/**
 * generate — full pipeline. Returns the output PDF path on success.
 */
export async function generate(opts: GenerateOptions): Promise<string> {
  const progress = new ProgressReporter(opts);
  const input = path.resolve(opts.input);

  if (!fs.existsSync(input)) {
    throw new Error(`input file not found: ${input}`);
  }

  const to = opts.to ?? "pdf";
  const outputPath = path.resolve(
    opts.output ?? path.join(os.tmpdir(), `${deriveSlug(input)}.${to}`),
  );

  // Stage 1: read markdown
  progress.begin("Reading markdown");
  const markdown = fs.readFileSync(input, "utf8");
  progress.end("Reading markdown");

  // Stage 1.5: diagram pre-pass — extract ```mermaid/```excalidraw fences and
  // swap in placeholder tokens. Rendering happens after the tab opens below.
  const extraction = extractDiagramFences(markdown);

  // Stage 2: render HTML
  progress.begin("Rendering HTML");

View on GitHub (pinned to 94993f7401)

Solutions

  1. Verify the file exists at the absolute path printed in the message.
  2. Pass an absolute path or run from the directory containing the markdown.
  3. Quote paths containing spaces.
  4. If using a glob, expand it in the shell or pass a single resolved file.

Example fix

# before
$ pdf --strict reprot.md   # typo
Error: input file not found: /cwd/reprot.md

# after
$ pdf --strict report.md
Defensive patterns

Strategy: validation

Validate before calling

import fs from 'node:fs';
import path from 'node:path';

function validateInput(input: string): string {
  const abs = path.resolve(input);
  if (!fs.existsSync(abs)) throw new Error(`input file not found: ${abs}`);
  if (!fs.statSync(abs).isFile()) throw new Error(`input is not a file: ${abs}`);
  return abs;
}

const input = validateInput(opts.input);

Prevention

When it happens

Trigger: Calling generate({input}) where path.resolve(opts.input) does not exist on disk. A typo in the filename, a relative path resolved against an unexpected CWD, a glob passed instead of a file, or a file that was deleted between the CLI parse and the run.

Common situations: Typo in the CLI argument (`pdf reprot.md`); CWD mismatch (running from a different directory than the markdown); a shell glob the shell did not expand; a build step that moved/deleted the input; a path with spaces needing quotes.

Related errors


AI-assisted analysis of garrytan/gstack@94993f7401 (2026-08-12). Data as JSON: /api/errors/1dfc9a6faae046f2. Report an issue: GitHub.