garrytan/gstack · warning · PdftotextUnavailableError

pdftotext not found. make-pdf needs pdftotext to run the co

Error message

pdftotext not found.

make-pdf needs pdftotext to run the copy-paste CI gate.
(Runtime rendering does NOT need it. This only affects tests.)

To install:
  macOS:    brew install poppler
  Ubuntu:   sudo apt-get install poppler-utils
  Fedora:   sudo dnf install poppler-utils
  Windows:  scoop install poppler  (or download from
            https://github.com/oschwartz10612/poppler-windows)

Or set GSTACK_PDFTOTEXT_BIN to an explicit path:
  ${GSTACK_PDFTOTEXT_BIN export/setx line}

What it means

PdftotextUnavailableError thrown by resolvePdftotext() when the pdftotext binary cannot be found via GSTACK_PDFTOTEXT_BIN/PDFTOTEXT_BIN env overrides, PATH lookup (Bun.which), or the POSIX standard locations (/opt/homebrew/bin, /usr/local/bin, /usr/bin). Note: runtime PDF rendering does NOT need pdftotext — only the copy-paste CI gate does. The message is a per-platform install recipe.

Source

Thrown at make-pdf/src/pdftotext.ts:97

  // 3: PATH lookup via Bun.which — handles Windows PATHEXT natively.
  const PATH = env.PATH ?? env.Path ?? '';
  const onPath = Bun.which('pdftotext', { PATH });
  if (onPath) return describeBinary(onPath);

  // 4: POSIX-only standard locations. No Windows candidates — Poppler installs
  // scatter across Scoop/Chocolatey/portable zips and guessing causes false
  // positives. Windows users set GSTACK_PDFTOTEXT_BIN explicitly.
  const posixCandidates = [
    "/opt/homebrew/bin/pdftotext",     // Apple Silicon Homebrew
    "/usr/local/bin/pdftotext",        // Intel Mac or Linuxbrew
    "/usr/bin/pdftotext",              // distro package
  ];
  for (const candidate of posixCandidates) {
    if (isExecutable(candidate)) return describeBinary(candidate);
  }

  throw new PdftotextUnavailableError([
    "pdftotext not found.",
    "",
    "make-pdf needs pdftotext to run the copy-paste CI gate.",
    "(Runtime rendering does NOT need it. This only affects tests.)",
    "",
    "To install:",
    "  macOS:    brew install poppler",
    "  Ubuntu:   sudo apt-get install poppler-utils",
    "  Fedora:   sudo dnf install poppler-utils",
    "  Windows:  scoop install poppler  (or download from",
    "            https://github.com/oschwartz10612/poppler-windows)",
    "",
    "Or set GSTACK_PDFTOTEXT_BIN to an explicit path:",
    process.platform === "win32"
      ? '  setx GSTACK_PDFTOTEXT_BIN "C:\\path\\to\\pdftotext.exe"'
      : "  export GSTACK_PDFTOTEXT_BIN=/path/to/pdftotext",
  ].join("\n"));
}

View on GitHub (pinned to 94993f7401)

Solutions

  1. Install poppler: `brew install poppler` (macOS), `sudo apt-get install poppler-utils` (Ubuntu), `sudo dnf install poppler-utils` (Fedora), `scoop install poppler` (Windows).
  2. Set GSTACK_PDFTOTEXT_BIN to an absolute pdftotext path (`export GSTACK_PDFTOTEXT_BIN=/usr/local/bin/pdftotext`).
  3. Skip the affected test gate if pdftotext is optional in your flow.
  4. On Windows, download poppler-windows and setx GSTACK_PDFTOTEXT_BIN to the bin/pdftotext.exe path.

Example fix

# before
$ bun test
Error: pdftotext not found. ...

# after — install poppler
$ brew install poppler
$ bun test
Defensive patterns

Strategy: validation

Validate before calling

import { resolvePdftotext, PdftotextUnavailableError } from './pdftotext';

function ensurePdftotext(): void {
  try { resolvePdftotext(); }
  catch (e) {
    if (e instanceof PdftotextUnavailableError) {
      throw new Error('pdftotext missing — install poppler or set GSTACK_PDFTOTEXT_BIN. Tests only; rendering unaffected.');
    }
    throw e;
  }
}

ensurePdftotext();

Type guard

import { PdftotextUnavailableError } from './pdftotext';
function isPdftotextMissing(e: unknown): e is PdftotextUnavailableError {
  return e instanceof PdftotextUnavailableError;
}

Try / catch

try {
  const text = pdftotext(pdfPath);
} catch (e) {
  if (e instanceof PdftotextUnavailableError) {
    console.warn('skipping copy-paste gate: pdftotext not installed');
    return; // non-fatal for local dev
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling pdftotext() (or the CI gate that uses it) on a machine without poppler installed and without GSTACK_PDFTOTEXT_BIN set. On Windows there are no standard-location guesses; the env override is required.

Common situations: A new dev machine without poppler; CI that runs the test suite but never installed poppler-utils; a Windows user who did not set GSTACK_PDFTOTEXT_BIN; a minimal Docker image that omitted poppler to save size; Homebrew installed to a non-standard prefix.

Related errors


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