{"record":{"id":"3fbbb0126af266c2","repo":"browsh-org/browsh","slug":"firefox-binary-not-found","errorCode":null,"errorMessage":"Firefox binary not found: ","messagePattern":"Firefox binary not found: ","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"interfacer/src/browsh/firefox.go","lineNumber":120,"sourceCode":"\t\tShutdown(errors.New(\"A headless Firefox is already running\"))\n\t}\n}\n\nfunc ensureFirefoxBinary() string {\n\tpath := viper.GetString(\"firefox.path\")\n\tif path == \"firefox\" {\n\t\tswitch runtime.GOOS {\n\t\tcase \"windows\":\n\t\t\tpath = getFirefoxPath()\n\t\tcase \"darwin\":\n\t\t\tpath = \"/Applications/Firefox.app/Contents/MacOS/firefox\"\n\t\tdefault:\n\t\t\tpath = getFirefoxPath()\n\t\t}\n\t}\n\tif _, err := os.Stat(path); err != nil {\n\t\tif errors.Is(err, fs.ErrNotExist) {\n\t\t\terr = errors.New(\"Firefox binary not found: \" + path)\n\t\t}\n\t\tShutdown(err)\n\t}\n\tslog.Info(\"Using Firefox\", \"path\", path)\n\treturn path\n}\n\n// Taken from https://stackoverflow.com/a/18411978/575773\nfunc versionOrdinal(version string) string {\n\t// ISO/IEC 14651:2011\n\tconst maxByte = 1<<8 - 1\n\tvo := make([]byte, 0, len(version)+8)\n\tj := -1\n\tfor i := 0; i < len(version); i++ {\n\t\tb := version[i]\n\t\tif '0' > b || b > '9' {\n\t\t\tvo = append(vo, b)\n\t\t\tj = -1","sourceCodeStart":102,"sourceCodeEnd":138,"githubUrl":"https://github.com/browsh-org/browsh/blob/499ef386d45cd1e2b5457dd04887c017f77b7e27/interfacer/src/browsh/firefox.go#L102-L138","documentation":"`ensureFirefoxBinary` resolves the Firefox executable path (from `firefox.path` config or platform-specific lookup) and stats it. If the file does not exist, browsh cannot launch Firefox at all, so it wraps the path into this error and calls `Shutdown`. The message includes the resolved path, so a trailing colon with an empty value means the platform lookup returned an empty path.","triggerScenarios":"`os.Stat(path)` returns an error with `fs.ErrNotExist` during `startHeadlessFirefox`. Happens when the `firefox.path` config value points to a nonexistent binary, or the platform lookup (`getFirefoxPath`) finds nothing (empty path).","commonSituations":"Firefox not installed or installed under a name the lookup doesn't cover (snap/flatpak installs); typo'd `firefox.path` in the .toml config; headless servers with no Firefox; flatpak Firefox where the binary isn't on PATH.","solutions":["Set `firefox.path` in your browsh config (.toml) to the full path of a Firefox binary (e.g. `/usr/bin/firefox`).","Verify with `which firefox` or `ls <path>` that the binary actually exists and is executable.","If using snap/flatpak Firefox, install a native (deb/rpm) Firefox or point firefox.path at the real binary path inside the snap/flatpak.","Install Firefox: `apt install firefox` (or equivalent), then retry browsh."],"exampleFix":"// before (config .toml)\n[firefox]\npath = \"/opt/firefox/firefox-bin\"  # does not exist\n// after\n[firefox]\npath = \"/usr/bin/firefox\"","handlingStrategy":"validation","validationCode":"const fs = require('fs');\nconst path = '/usr/bin/firefox'; // same value as firefox.path config\nif (!fs.existsSync(path)) throw new Error(`Firefox binary missing at ${path}`);","typeGuard":"function firefoxPathIsValid(p) {\n  return typeof p === 'string' && p.length > 0 && fs.existsSync(p);\n}","tryCatchPattern":"try {\n  startBrowsh();\n} catch (e) {\n  if (/Firefox binary not found/.test(e.message)) {\n    console.error('Set firefox.path in config to an existing binary:', e.message);\n  } else { throw e; }\n}","preventionTips":["Verify `which firefox` resolves on the target machine before installing browsh.","Set an explicit absolute `firefox.path` in config instead of relying on lookup.","On snap/flatpak systems, point firefox.path at a native Firefox binary.","In Docker images, install Firefox explicitly and assert it exists in your entrypoint."],"tags":["firefox","configuration","missing-binary"],"backgroundTag":"binary-not-found","analyzedSha":"499ef386d45cd1e2b5457dd04887c017f77b7e27","analyzedAt":"2026-09-02T19:05:32.228Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-09T21:17:11.164Z"}