{"record":{"id":"0fbe0f481921301d","repo":"garrytan/gstack","slug":"pdftotext-not-found-make-pdf-needs-pdftotext-to","errorCode":null,"errorMessage":"pdftotext not found.\n\nmake-pdf needs pdftotext to run the copy-paste CI gate.\n(Runtime rendering does NOT need it. This only affects tests.)\n\nTo install:\n  macOS:    brew install poppler\n  Ubuntu:   sudo apt-get install poppler-utils\n  Fedora:   sudo dnf install poppler-utils\n  Windows:  scoop install poppler  (or download from\n            https://github.com/oschwartz10612/poppler-windows)\n\nOr set GSTACK_PDFTOTEXT_BIN to an explicit path:\n  ${GSTACK_PDFTOTEXT_BIN export/setx line}","messagePattern":"pdftotext not found\\.\n\nmake-pdf needs pdftotext to run the copy-paste CI gate\\.\n\\(Runtime rendering does NOT need it\\. This only affects tests\\.\\)\n\nTo install:\n  macOS:    brew install poppler\n  Ubuntu:   sudo apt-get install poppler-utils\n  Fedora:   sudo dnf install poppler-utils\n  Windows:  scoop install poppler  \\(or download from\n            https://github\\.com/oschwartz10612/poppler-windows\\)\n\nOr set GSTACK_PDFTOTEXT_BIN to an explicit path:\n  (.+?)","errorType":"exception","errorClass":"PdftotextUnavailableError","httpStatus":null,"severity":"warning","filePath":"make-pdf/src/pdftotext.ts","lineNumber":97,"sourceCode":"\n  // 3: PATH lookup via Bun.which — handles Windows PATHEXT natively.\n  const PATH = env.PATH ?? env.Path ?? '';\n  const onPath = Bun.which('pdftotext', { PATH });\n  if (onPath) return describeBinary(onPath);\n\n  // 4: POSIX-only standard locations. No Windows candidates — Poppler installs\n  // scatter across Scoop/Chocolatey/portable zips and guessing causes false\n  // positives. Windows users set GSTACK_PDFTOTEXT_BIN explicitly.\n  const posixCandidates = [\n    \"/opt/homebrew/bin/pdftotext\",     // Apple Silicon Homebrew\n    \"/usr/local/bin/pdftotext\",        // Intel Mac or Linuxbrew\n    \"/usr/bin/pdftotext\",              // distro package\n  ];\n  for (const candidate of posixCandidates) {\n    if (isExecutable(candidate)) return describeBinary(candidate);\n  }\n\n  throw new PdftotextUnavailableError([\n    \"pdftotext not found.\",\n    \"\",\n    \"make-pdf needs pdftotext to run the copy-paste CI gate.\",\n    \"(Runtime rendering does NOT need it. This only affects tests.)\",\n    \"\",\n    \"To install:\",\n    \"  macOS:    brew install poppler\",\n    \"  Ubuntu:   sudo apt-get install poppler-utils\",\n    \"  Fedora:   sudo dnf install poppler-utils\",\n    \"  Windows:  scoop install poppler  (or download from\",\n    \"            https://github.com/oschwartz10612/poppler-windows)\",\n    \"\",\n    \"Or set GSTACK_PDFTOTEXT_BIN to an explicit path:\",\n    process.platform === \"win32\"\n      ? '  setx GSTACK_PDFTOTEXT_BIN \"C:\\\\path\\\\to\\\\pdftotext.exe\"'\n      : \"  export GSTACK_PDFTOTEXT_BIN=/path/to/pdftotext\",\n  ].join(\"\\n\"));\n}","sourceCodeStart":79,"sourceCodeEnd":115,"githubUrl":"https://github.com/garrytan/gstack/blob/94993f74012782fd94416dd44b8314f6363a13a4/make-pdf/src/pdftotext.ts#L79-L115","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Install poppler: `brew install poppler` (macOS), `sudo apt-get install poppler-utils` (Ubuntu), `sudo dnf install poppler-utils` (Fedora), `scoop install poppler` (Windows).","Set GSTACK_PDFTOTEXT_BIN to an absolute pdftotext path (`export GSTACK_PDFTOTEXT_BIN=/usr/local/bin/pdftotext`).","Skip the affected test gate if pdftotext is optional in your flow.","On Windows, download poppler-windows and setx GSTACK_PDFTOTEXT_BIN to the bin/pdftotext.exe path."],"exampleFix":"# before\n$ bun test\nError: pdftotext not found. ...\n\n# after — install poppler\n$ brew install poppler\n$ bun test","handlingStrategy":"validation","validationCode":"import { resolvePdftotext, PdftotextUnavailableError } from './pdftotext';\n\nfunction ensurePdftotext(): void {\n  try { resolvePdftotext(); }\n  catch (e) {\n    if (e instanceof PdftotextUnavailableError) {\n      throw new Error('pdftotext missing — install poppler or set GSTACK_PDFTOTEXT_BIN. Tests only; rendering unaffected.');\n    }\n    throw e;\n  }\n}\n\nensurePdftotext();","typeGuard":"import { PdftotextUnavailableError } from './pdftotext';\nfunction isPdftotextMissing(e: unknown): e is PdftotextUnavailableError {\n  return e instanceof PdftotextUnavailableError;\n}","tryCatchPattern":"try {\n  const text = pdftotext(pdfPath);\n} catch (e) {\n  if (e instanceof PdftotextUnavailableError) {\n    console.warn('skipping copy-paste gate: pdftotext not installed');\n    return; // non-fatal for local dev\n  }\n  throw e;\n}","preventionTips":["Install poppler in every CI image that runs the test suite.","Set GSTACK_PDFTOTEXT_BIN to an absolute path in CI for reproducibility.","Treat the absence as test-only — never block a render on it.","Document the dependency in the repo's setup instructions."],"tags":["make-pdf","pdftotext","binary-resolution","ci","poppler"],"backgroundTag":null,"analyzedSha":"94993f74012782fd94416dd44b8314f6363a13a4","analyzedAt":"2026-08-12T04:06:23.140Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}