{"record":{"id":"032b1db3ea8e97d3","repo":"zeroclaw-labs/zeroclaw","slug":"runtime-shell-shell-resolved-to-does-not","errorCode":null,"errorMessage":"runtime.shell {shell:?} (resolved to {}) does not exist","messagePattern":"runtime\\.shell (.+?) \\(resolved to (.+?)\\) does not exist","errorType":"validation","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/zeroclaw-config/src/platform/mod.rs","lineNumber":61,"sourceCode":"        path.to_path_buf()\n    } else if path.components().count() > 1 {\n        anyhow::bail!(\n            \"runtime.shell {shell:?} is a relative path; use a bare name resolved on PATH (e.g. \\\"bash\\\") or an absolute path (e.g. \\\"/bin/bash\\\")\"\n        );\n    } else {\n        match std::env::split_paths(&std::env::var_os(\"PATH\").unwrap_or_default())\n            .map(|dir| dir.join(shell))\n            .find(|candidate| candidate.is_file())\n        {\n            Some(found) => found,\n            None => anyhow::bail!(\n                \"runtime.shell {shell:?} was not found on PATH; use an absolute path or install the shell\"\n            ),\n        }\n    };\n\n    if !resolved.exists() {\n        anyhow::bail!(\n            \"runtime.shell {shell:?} (resolved to {}) does not exist\",\n            resolved.display()\n        );\n    }\n\n    let metadata = match resolved.metadata() {\n        Ok(metadata) => metadata,\n        Err(e) => anyhow::bail!(\n            \"runtime.shell {shell:?} (resolved to {}) could not be inspected: {e}\",\n            resolved.display()\n        ),\n    };\n    if !metadata.is_file() {\n        anyhow::bail!(\n            \"runtime.shell {shell:?} (resolved to {}) is not a regular file\",\n            resolved.display()\n        );\n    }","sourceCodeStart":43,"sourceCodeEnd":79,"githubUrl":"https://github.com/zeroclaw-labs/zeroclaw/blob/88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc/crates/zeroclaw-config/src/platform/mod.rs#L43-L79","documentation":"After resolution (absolute path taken as-is, bare name found on PATH), validate_shell verifies the resolved target exists. For absolute inputs this is the first real check, so it primarily catches dead absolute paths; for PATH-resolved names it covers the race where the file vanished between lookup and stat.","triggerScenarios":"runtime.shell = \"/usr/bin/fish\" on a machine without fish; a stale absolute path after the shell was upgraded, moved, or removed; a PATH-found file deleted between resolution and the exists() check.","commonSituations":"Config copied between machines with different layouts; brew or apt upgrades relocating shells; containers whose runtime image differs from the dev box the config was written on.","solutions":["Confirm the path exists (ls it), then point at a shell that is actually present.","Prefer a bare name (\"bash\") so each machine's PATH picks the right location.","In the docker runtime, ensure the shell is installed in the container image the config targets.","Use /bin/sh as the portable floor when targeting heterogeneous machines."],"exampleFix":"# before\n[runtime]\nshell = \"/usr/bin/fish\"   # does not exist on this machine\n\n# after\n[runtime]\nshell = \"bash\"   # resolved per-machine via PATH","handlingStrategy":"validation","validationCode":"let resolved = if std::path::Path::new(shell).is_absolute() {\n    std::path::PathBuf::from(shell)\n} else {\n    resolve_on_path(shell)? // your own PATH walk\n};\nif !resolved.exists() { /* point at an installed shell before create_runtime */ }","typeGuard":null,"tryCatchPattern":"match create_runtime(&config) {\n    Err(e) if e.to_string().contains(\"does not exist\") => {\n        // verify with ls / file, switch to a bare name or /bin/sh, retry\n    }\n    other => other,\n}","preventionTips":["Verify absolute shell paths per machine; prefer bare names for portability.","For docker runtime, confirm the shell exists in the container image, not just the host.","Re-check configs after OS upgrades that move or remove shells."],"tags":["runtime","shell","missing-file"],"backgroundTag":"shell-binary-missing","analyzedSha":"88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc","analyzedAt":"2026-08-23T01:07:41.857Z","schemaVersion":2},"datasetVersion":"2026-08-23T08:06:27.607Z"}