zeroclaw-labs/zeroclaw · error · anyhow::Error
Requested text browser '{browser}' is not installed
Error message
Requested text browser '{browser}' is not installed What it means
After a requested browser name passes the supported-list check, resolve_browser verifies the binary exists by running `which <browser>` and requiring a successful exit. If the command fails or the process cannot spawn, the tool concludes the browser is not installed and bails.
Source
Thrown at crates/zeroclaw-tools/src/text_browser.rs:159
async fn resolve_browser(&self, requested: Option<&str>) -> anyhow::Result<String> {
// If the caller explicitly requested a browser via the tool parameter, use it.
if let Some(browser) = requested {
let browser = browser.trim().to_lowercase();
if !SUPPORTED_BROWSERS.contains(&browser.as_str()) {
anyhow::bail!(
"Unsupported text browser '{browser}'. Supported: {}",
SUPPORTED_BROWSERS.join(", ")
);
}
// Verify it's installed
let installed = tokio::process::Command::new("which")
.arg(&browser)
.output()
.await
.map(|o| o.status.success())
.unwrap_or(false);
if !installed {
anyhow::bail!("Requested text browser '{browser}' is not installed");
}
return Ok(browser);
}
// If a preferred browser is set in config, try it first.
if let Some(ref preferred) = self.preferred_browser {
let preferred = preferred.trim().to_lowercase();
if SUPPORTED_BROWSERS.contains(&preferred.as_str()) {
let installed = tokio::process::Command::new("which")
.arg(&preferred)
.output()
.await
.map(|o| o.status.success())
.unwrap_or(false);
if installed {
return Ok(preferred);
}
::zeroclaw_log::record!(View on GitHub (pinned to 88bb9c8533)
Solutions
- Install the browser: Debian/Ubuntu `apt-get install -y lynx`, Alpine `apk add lynx`, macOS `brew install lynx` / `brew install w3m`
- Verify with `which lynx` in the same environment the tool runs in
- Or omit the browser parameter so auto-detection picks whichever of the three is installed
Example fix
# before: container without a text browser $ docker run myagent zeroclaw ... browser=w3m # bails # after $ docker run myagent sh -c "apk add w3m && zeroclaw ... browser=w3m"
Defensive patterns
Strategy: fallback
Validate before calling
// Cheap preflight: check the binary resolves before invoking the tool
async fn browser_installed(name: &str) -> bool {
tokio::process::Command::new("which").arg(name).output()
.await.map(|o| o.status.success()).unwrap_or(false)
} Try / catch
Err(e) if e.to_string().contains("is not installed") => {
// fall back: retry with browser omitted so auto-detect picks an installed one
} Prevention
- Install lynx/links/w3m in Dockerfiles and CI images as a base dependency
- Add a startup check that at least one supported browser resolves via which
- Prefer passing no browser name and letting auto-detection pick what exists
When it happens
Trigger: Requesting "w3m" or "lynx" on a minimal container, fresh server, or CI image where none of the three browsers were installed; PATH not including the binary's directory under custom shells (NixOS, homebrew on Linux).
Common situations: Docker/minimal images used for agent runtimes; macOS machines without lynx/w3m preinstalled; environments where `which` itself is absent (some minimal images ship `command -v` only), which the unwrap_or(false) treats as not installed.
Related errors
- Source path does not exist: {source}
- Slack outbound attachment path must be absolute: {target}
- Docker runtime requires an absolute workspace path, got: {}
- runtime.shell {shell:?} was not found on PATH; use an absolu
- probe-rs not found. Install it: cargo install probe-rs-too
AI-assisted analysis of zeroclaw-labs/zeroclaw@88bb9c8533 (2026-08-23).
Data as JSON: /api/errors/f60417f53d193bd1.
Report an issue: GitHub.