{"record":{"id":"f60417f53d193bd1","repo":"zeroclaw-labs/zeroclaw","slug":"requested-text-browser-browser-is-not-installe","errorCode":null,"errorMessage":"Requested text browser '{browser}' is not installed","messagePattern":"Requested text browser '(.+?)' is not installed","errorType":"validation","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/zeroclaw-tools/src/text_browser.rs","lineNumber":159,"sourceCode":"    async fn resolve_browser(&self, requested: Option<&str>) -> anyhow::Result<String> {\n        // If the caller explicitly requested a browser via the tool parameter, use it.\n        if let Some(browser) = requested {\n            let browser = browser.trim().to_lowercase();\n            if !SUPPORTED_BROWSERS.contains(&browser.as_str()) {\n                anyhow::bail!(\n                    \"Unsupported text browser '{browser}'. Supported: {}\",\n                    SUPPORTED_BROWSERS.join(\", \")\n                );\n            }\n            // Verify it's installed\n            let installed = tokio::process::Command::new(\"which\")\n                .arg(&browser)\n                .output()\n                .await\n                .map(|o| o.status.success())\n                .unwrap_or(false);\n            if !installed {\n                anyhow::bail!(\"Requested text browser '{browser}' is not installed\");\n            }\n            return Ok(browser);\n        }\n\n        // If a preferred browser is set in config, try it first.\n        if let Some(ref preferred) = self.preferred_browser {\n            let preferred = preferred.trim().to_lowercase();\n            if SUPPORTED_BROWSERS.contains(&preferred.as_str()) {\n                let installed = tokio::process::Command::new(\"which\")\n                    .arg(&preferred)\n                    .output()\n                    .await\n                    .map(|o| o.status.success())\n                    .unwrap_or(false);\n                if installed {\n                    return Ok(preferred);\n                }\n                ::zeroclaw_log::record!(","sourceCodeStart":141,"sourceCodeEnd":177,"githubUrl":"https://github.com/zeroclaw-labs/zeroclaw/blob/88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc/crates/zeroclaw-tools/src/text_browser.rs#L141-L177","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","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"],"exampleFix":"# before: container without a text browser\n$ docker run myagent zeroclaw ... browser=w3m   # bails\n# after\n$ docker run myagent sh -c \"apk add w3m && zeroclaw ... browser=w3m\"","handlingStrategy":"fallback","validationCode":"// Cheap preflight: check the binary resolves before invoking the tool\nasync fn browser_installed(name: &str) -> bool {\n    tokio::process::Command::new(\"which\").arg(name).output()\n        .await.map(|o| o.status.success()).unwrap_or(false)\n}","typeGuard":null,"tryCatchPattern":"Err(e) if e.to_string().contains(\"is not installed\") => {\n    // fall back: retry with browser omitted so auto-detect picks an installed one\n}","preventionTips":["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"],"tags":["browser","dependency","path","install"],"backgroundTag":"command-not-found","analyzedSha":"88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc","analyzedAt":"2026-08-23T01:07:41.857Z","schemaVersion":2},"datasetVersion":"2026-08-23T08:06:27.607Z"}