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

  1. Export a valid shell before running doctor/the daemon: `export SHELL=/bin/bash`.
  2. For systemd units add `Environment="SHELL=/bin/bash"` to the `[Service]` section.
  3. On Windows ensure `ComSpec` points at `cmd.exe`.
  4. 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

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


AI-assisted analysis of zeroclaw-labs/zeroclaw@88bb9c8533 (2026-08-23). Data as JSON: /api/errors/fd5f43e0bcde2504. Report an issue: GitHub.