browsh-org/browsh · critical
Firefox binary not found:
Error message
Firefox binary not found:
What it means
`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.
Source
Thrown at interfacer/src/browsh/firefox.go:120
Shutdown(errors.New("A headless Firefox is already running"))
}
}
func ensureFirefoxBinary() string {
path := viper.GetString("firefox.path")
if path == "firefox" {
switch runtime.GOOS {
case "windows":
path = getFirefoxPath()
case "darwin":
path = "/Applications/Firefox.app/Contents/MacOS/firefox"
default:
path = getFirefoxPath()
}
}
if _, err := os.Stat(path); err != nil {
if errors.Is(err, fs.ErrNotExist) {
err = errors.New("Firefox binary not found: " + path)
}
Shutdown(err)
}
slog.Info("Using Firefox", "path", path)
return path
}
// Taken from https://stackoverflow.com/a/18411978/575773
func versionOrdinal(version string) string {
// ISO/IEC 14651:2011
const maxByte = 1<<8 - 1
vo := make([]byte, 0, len(version)+8)
j := -1
for i := 0; i < len(version); i++ {
b := version[i]
if '0' > b || b > '9' {
vo = append(vo, b)
j = -1View on GitHub (pinned to 499ef386d4)
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.
Example fix
// before (config .toml) [firefox] path = "/opt/firefox/firefox-bin" # does not exist // after [firefox] path = "/usr/bin/firefox"
Defensive patterns
Strategy: validation
Validate before calling
const fs = require('fs');
const path = '/usr/bin/firefox'; // same value as firefox.path config
if (!fs.existsSync(path)) throw new Error(`Firefox binary missing at ${path}`); Type guard
function firefoxPathIsValid(p) {
return typeof p === 'string' && p.length > 0 && fs.existsSync(p);
} Try / catch
try {
startBrowsh();
} catch (e) {
if (/Firefox binary not found/.test(e.message)) {
console.error('Set firefox.path in config to an existing binary:', e.message);
} else { throw e; }
} Prevention
- 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.
When it happens
Trigger: `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).
Common situations: 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.
Related errors
- A headless Firefox is already running
- There appears to already be an existing Web Extension connec
- Failed to connect to Firefox's Marionette within 30 seconds
- Installed Firefox version is too old. Firefox 57 or newer i
- Could not find Firefox on your registry
AI-assisted analysis of browsh-org/browsh@499ef386d4 (2026-09-02).
Data as JSON: /api/errors/3fbbb0126af266c2.
Report an issue: GitHub.