{"record":{"id":"badaff75c1e0ba06","repo":"garrytan/gstack","slug":"127","errorCode":"127","errorMessage":"browse resolve exited 127: browse binary not found.\n\nmake-pdf needs browse (the gstack Chromium daemon) to render PDFs.\nTried:\n  - $GSTACK_BROWSE_BIN (${env.GSTACK_BROWSE_BIN || \"unset\"})\n  - $BROWSE_BIN (${env.BROWSE_BIN || \"unset\"})\n  - sibling: ${siblingCandidates.join(\", \")}\n  - global: ${globalPath}\n  - PATH: `browse`\n\nTo fix: run gstack setup from the gstack repo:\n  cd ~/.claude/skills/gstack && ./setup\n\nOr set GSTACK_BROWSE_BIN explicitly:\n  ${GSTACK_BROWSE_BIN export/setx line}","messagePattern":"browse resolve exited 127: browse binary not found\\.\n\nmake-pdf needs browse \\(the gstack Chromium daemon\\) to render PDFs\\.\nTried:\n  - \\$GSTACK_BROWSE_BIN \\((.+?)\\)\n  - \\$BROWSE_BIN \\((.+?)\\)\n  - sibling: (.+?)\n  - global: (.+?)\n  - PATH: `browse`\n\nTo fix: run gstack setup from the gstack repo:\n  cd ~/\\.claude/skills/gstack && \\./setup\n\nOr set GSTACK_BROWSE_BIN explicitly:\n  (.+?)","errorType":"exception","errorClass":"BrowseClientError","httpStatus":null,"severity":"error","filePath":"make-pdf/src/browseClient.ts","lineNumber":134,"sourceCode":"  ];\n  for (const candidate of siblingCandidates) {\n    const found = findExecutable(candidate);\n    if (found) return found;\n  }\n\n  // 4: global install.\n  const home = os.homedir();\n  const globalPath = path.join(home, \".claude/skills/gstack/browse/dist/browse\");\n  const globalFound = findExecutable(globalPath);\n  if (globalFound) return globalFound;\n\n  // 5: PATH lookup via Bun.which — handles Windows PATHEXT natively (no `which`\n  // dependency on cmd.exe / PowerShell, no `where`-vs-`which` branch).\n  const PATH = env.PATH ?? env.Path ?? '';\n  const onPath = Bun.which('browse', { PATH });\n  if (onPath) return onPath;\n\n  throw new BrowseClientError(\n    /* exitCode */ 127,\n    \"resolve\",\n    [\n      \"browse binary not found.\",\n      \"\",\n      \"make-pdf needs browse (the gstack Chromium daemon) to render PDFs.\",\n      \"Tried:\",\n      `  - $GSTACK_BROWSE_BIN (${env.GSTACK_BROWSE_BIN || \"unset\"})`,\n      `  - $BROWSE_BIN (${env.BROWSE_BIN || \"unset\"})`,\n      `  - sibling: ${siblingCandidates.join(\", \")}`,\n      `  - global: ${globalPath}`,\n      \"  - PATH: `browse`\",\n      \"\",\n      \"To fix: run gstack setup from the gstack repo:\",\n      \"  cd ~/.claude/skills/gstack && ./setup\",\n      \"\",\n      \"Or set GSTACK_BROWSE_BIN explicitly:\",\n      process.platform === \"win32\"","sourceCodeStart":116,"sourceCodeEnd":152,"githubUrl":"https://github.com/garrytan/gstack/blob/94993f74012782fd94416dd44b8314f6363a13a4/make-pdf/src/browseClient.ts#L116-L152","documentation":"BrowseClientError with exitCode 127 thrown by resolveBrowseBin() when the browse binary cannot be located in any of five resolution tiers: GSTACK_BROWSE_BIN/BROWSE_BIN env overrides, sibling dist paths, the global ~/.claude/skills/gstack install, or PATH. make-pdf needs browse (the gstack Chromium daemon) to render PDFs. The message is a canonical setup recipe, not just a path.","triggerScenarios":"First make-pdf run on a machine where gstack ./setup was never run; GSTACK_BROWSE_BIN points to a deleted/moved binary; a compiled pdf binary invoked from a directory whose sibling/browse layout differs from the expected dist/ layout; PATH lacks the browse install dir; the global install was partially deleted.","commonSituations":"Fresh CI worker without the gstack skill installed; a user who only `bun install`-ed make-pdf without building browse; moving the repo after setting a relative GSTACK_BROWSE_BIN; macOS Gatekeeper quarantine stripping the executable bit; Windows where the .exe extension requires PATHEXT resolution that Bun.which handles but a hand-set env var does not.","solutions":["Run `cd ~/.claude/skills/gstack && ./setup` to (re)build and install browse.","Set GSTACK_BROWSE_BIN to an absolute path of an existing browse binary (`export GSTACK_BROWSE_BIN=/path/to/browse`).","Confirm the binary is executable: `chmod +x <browse>` (POSIX) or unblock it (Windows).","Run `bun run build` in the gstack repo to produce browse/dist/browse, then retry."],"exampleFix":"# before\n$ pdf report.md\nError: browse resolve exited 127: browse binary not found. ...\n\n# after — install browse, then render\n$ cd ~/.claude/skills/gstack && ./setup\n$ export GSTACK_BROWSE_BIN=\"$HOME/.claude/skills/gstack/browse/dist/browse\"\n$ pdf report.md","handlingStrategy":"validation","validationCode":"import { resolveBrowseBin, BrowseClientError } from './browseClient';\nimport fs from 'node:fs';\n\nfunction ensureBrowseAvailable(env = process.env): void {\n  try {\n    const bin = resolveBrowseBin(env);\n    if (!fs.existsSync(bin)) throw new Error(`resolved browse binary missing: ${bin}`);\n  } catch (e) {\n    if (e instanceof BrowseClientError && e.exitCode === 127) {\n      throw new Error('Run `cd ~/.claude/skills/gstack && ./setup` before rendering PDFs.');\n    }\n    throw e;\n  }\n}\n\nensureBrowseAvailable();","typeGuard":"import { BrowseClientError } from './browseClient';\nfunction isBrowseMissing(e: unknown): e is BrowseClientError {\n  return e instanceof BrowseClientError && e.exitCode === 127;\n}","tryCatchPattern":"try {\n  await generate(opts);\n} catch (e) {\n  if (isBrowseMissing(e)) {\n    console.error('browse not installed — run ./setup from the gstack repo, then retry.');\n    process.exit(127);\n  }\n  throw e;\n}","preventionTips":["Run gstack ./setup once on every new machine/CI worker.","Set GSTACK_BROWSE_BIN to an absolute path in CI for reproducibility.","Pin the browse build and make-pdf client to the same release.","Confirm the binary is executable (chmod +x / unblock on Windows)."],"tags":["make-pdf","browse","binary-resolution","setup","environment"],"backgroundTag":null,"analyzedSha":"94993f74012782fd94416dd44b8314f6363a13a4","analyzedAt":"2026-08-12T04:06:23.140Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}