zeroclaw-labs/zeroclaw · error · anyhow::Error
Gateway responded {status}: {err}
Error message
Gateway responded {status}: {err} What it means
The CLI reached the gateway but `GET /admin/sop/pending` returned a non-2xx status; the message embeds the HTTP status code plus the gateway's `error` string from the JSON body (or 'request failed' when the body carries none). Connection-level failures raise a separate 'Failed to connect to gateway' error.
Source
Thrown at src/main.rs:6879
let prefix = config.gateway.path_prefix.as_deref();
let client = reqwest::Client::new();
match cmd {
SopCommands::Pending => {
let url = gateway_admin_url(&host, port, prefix, "/admin/sop/pending");
let resp = client
.get(&url)
.timeout(std::time::Duration::from_secs(5))
.send()
.await
.map_err(|e| anyhow::Error::msg(format!("Failed to connect to gateway: {e}")))?;
let status = resp.status();
let body: serde_json::Value = resp.json().await.unwrap_or_default();
if !status.is_success() {
let err = body
.get("error")
.and_then(|v| v.as_str())
.unwrap_or("request failed");
anyhow::bail!("Gateway responded {status}: {err}");
}
let pending = body
.get("pending")
.and_then(|p| p.as_array())
.cloned()
.unwrap_or_default();
if pending.is_empty() {
println!(
"{}",
t("cli-sop-pending-none", "No SOP runs waiting for approval.")
);
} else {
println!(
"{}",
t("cli-sop-pending-header", "SOP runs waiting for approval:")
);
for r in pending {
let run_id = r.get("run_id").and_then(|v| v.as_str()).unwrap_or("?");View on GitHub (pinned to 88bb9c8533)
Solutions
- Confirm the service on `[gateway]` host/port is the ZeroClaw daemon and is healthy (gateway logs / status output)
- Align `[gateway]` host, port, and path_prefix in the CLI config with the daemon's actual settings
- Re-provision or fix the admin credential if the status is 401/403
- Upgrade the daemon if it predates the `/admin/sop/*` routes (404 with a correct prefix)
Example fix
# before: daemon serves under a prefix, CLI config has none [gateway] host = "127.0.0.1" port = 8080 # after [gateway] host = "127.0.0.1" port = 8080 path_prefix = "/zeroclaw"
Defensive patterns
Strategy: try-catch
Validate before calling
# preflight: daemon reachable and admin routes present
curl -fsS "http://${ZC_GW_HOST}:${ZC_GW_PORT}${ZC_GW_PREFIX}/admin/sop/pending" >/dev/null \
|| echo "gateway preflight failed" >&2 Try / catch
if ! out="$(zeroclaw sop pending 2>&1)"; then
case "$out" in
*"Failed to connect"*) echo "daemon unreachable"; exit 2 ;; # transport
*"Gateway responded 5"*) retry_with_backoff zeroclaw sop pending ;; # server-side
*"Gateway responded 4"*) echo "$out"; exit 1 ;; # config/auth: do not retry
esac
fi Prevention
- Share one `[gateway]` config source between CLI and daemon so host/port/prefix cannot drift
- Monitor daemon health before running SOP operations
- Alert on 4xx from admin endpoints as config drift, not transient failure
When it happens
Trigger: `zeroclaw sop pending` when the gateway returns 401/403 (admin authentication), 404 (`[gateway]` path_prefix mismatch or a daemon older than the SOP admin routes), or 5xx (daemon-side failure).
Common situations: The `[gateway]` block pointing at the wrong port or service; a path_prefix configured on the daemon but not the CLI (or vice versa); an admin credential expired or never provisioned; running a pre-SOP daemon version.
Related errors
- Gateway responded {status}: {detail}
- `zeroclaw sop approve/deny/pending` requires the agent-runti
- launchctl start failed: {}
- rc-service restart failed: {}
- systemctl restart failed: {}
AI-assisted analysis of zeroclaw-labs/zeroclaw@88bb9c8533 (2026-08-23).
Data as JSON: /api/errors/45bb881ea0850615.
Report an issue: GitHub.