zeroclaw-labs/zeroclaw · warning · DiagItem
neither $SHELL nor %ComSpec% is set
Error message
neither $SHELL nor %ComSpec% is set
What it means
A `zeroclaw doctor` warning from `check_environment`: neither the Unix `SHELL` nor the Windows `ComSpec` environment variable is set to a non-empty value. ZeroClaw shells out for tool execution and version probes, and this pair is its shell discovery order; when both are missing, shell-based operations degrade. On Windows the check expects `%ComSpec%` (path to cmd.exe).
Source
Thrown at crates/zeroclaw-runtime/src/doctor/mod.rs:1731
}
}
// ── Environment checks ───────────────────────────────────────────
fn check_environment(items: &mut Vec<DiagItem>) {
let cat = "environment";
// git
check_command_available("git", &["--version"], cat, items);
// Shell — Unix uses $SHELL, Windows uses %ComSpec% (path to cmd.exe).
let shell = std::env::var("SHELL")
.ok()
.filter(|s| !s.is_empty())
.or_else(|| std::env::var("ComSpec").ok().filter(|s| !s.is_empty()));
match shell {
Some(s) => items.push(DiagItem::ok(cat, format!("shell: {s}"))),
None => items.push(DiagItem::warn(cat, "neither $SHELL nor %ComSpec% is set")),
}
// HOME
if std::env::var("HOME").is_ok() || std::env::var("USERPROFILE").is_ok() {
items.push(DiagItem::ok(cat, "home directory env set"));
} else {
items.push(DiagItem::error(
cat,
"neither $HOME nor $USERPROFILE is set",
));
}
// Optional tools
check_command_available("curl", &["--version"], cat, items);
if crate::service::linux_systemd_runtime_present() {
items.push(systemd_linger_diag_item(
crate::service::systemd_user_linger_status(),View on GitHub (pinned to 88bb9c8533)
Solutions
- Export a valid shell before running doctor/the daemon: `export SHELL=/bin/bash`.
- For systemd units add `Environment="SHELL=/bin/bash"` to the `[Service]` section.
- On Windows ensure `ComSpec` points at `cmd.exe`.
- Re-run `zeroclaw doctor` and confirm the `shell: ...` ok line appears.
Example fix
# before (systemd unit): SHELL unset -> "neither $SHELL nor %ComSpec% is set" [Service] ExecStart=/usr/bin/zeroclaw daemon # after [Service] Environment="SHELL=/bin/bash" ExecStart=/usr/bin/zeroclaw daemon
Defensive patterns
Strategy: fallback
Validate before calling
let shell = std::env::var("SHELL").ok().filter(|s| !s.is_empty())
.or_else(|| std::env::var("ComSpec").ok().filter(|s| !s.is_empty()))
.unwrap_or_else(|| "/bin/sh".to_string()); Prevention
- Set `Environment="SHELL=/bin/bash"` in any systemd unit that runs zeroclaw.
- In containers, `ENV SHELL=/bin/sh` so shell discovery never depends on a login session.
When it happens
Trigger: Running `zeroclaw doctor` (or the daemon) in an environment where `SHELL` is unset — cron jobs, systemd services without a PAM session, minimal Docker images, some CI runners — and, on Windows, `ComSpec` unset.
Common situations: Daemon installed as a systemd user service where the unit has no shell environment; container images derived from `FROM scratch`-style minimal bases; CI pipelines that scrub env; Windows contexts with a stripped environment.
Understand the failure class
Background: "environment variable is not set" and "Missing keys in environment" errors: what missing required env var messages mean and how to fix them — this error's family across 28 libraries.
Related errors
- systemd user lingering disabled; user service may stop after
- systemd user lingering could not be checked with loginctl
- {cmd} found but returned non-zero
- {cmd} not found in PATH
- systemctl restart failed: {}
AI-assisted analysis of zeroclaw-labs/zeroclaw@88bb9c8533 (2026-08-23).
Data as JSON: /api/errors/fd5f43e0bcde2504.
Report an issue: GitHub.