zeroclaw-labs/zeroclaw · error

webhook-audit: {e}

Error message

webhook-audit: {e}

What it means

Raised by agent_delete_precheck (src/alias_cli/mod.rs:454), the hard gate that runs before `zeroclaw agents delete <alias>` mutates any config or owned state. It opens the data_dir-backed AcpSessionStore (crates/zeroclaw-gateway/src/agent_owned_state.rs:13) and counts live Agent Client Protocol sessions owned by the alias; a count > 0 aborts the delete because removing the alias would orphan live WebSocket sessions on the gateway's `/acp` route. The check mirrors the gateway's own delete gate and fails closed: if the session store cannot even be read, deletion is also refused (context error "could not verify live ACP sessions"). Nothing has been modified when this error surfaces.

Source

Thrown at crates/zeroclaw-runtime/src/hooks/builtin/webhook_audit.rs:133

                    .with_attrs(::serde_json::json!({"hook": "webhook-audit"})),
                "webhook-audit hook is enabled but no URL is configured — audit events will be dropped"
            );
        }

        // Validate URL against SSRF if one is provided.
        if !config.url.is_empty()
            && let Err(e) = validate_webhook_url(&config.url)
        {
            ::zeroclaw_log::record!(
                ERROR,
                ::zeroclaw_log::Event::new(module_path!(), ::zeroclaw_log::Action::Fail)
                    .with_outcome(::zeroclaw_log::EventOutcome::Failure)
                    .with_attrs(
                        ::serde_json::json!({"hook": "webhook-audit", "error": format!("{}", e)})
                    ),
                "webhook URL validation failed"
            );
            panic!("webhook-audit: {e}");
        }

        let client = reqwest::Client::builder()
            .timeout(Duration::from_secs(5))
            .build()
            .expect("failed to build webhook HTTP client");
        Self {
            config,
            client,
            pending_args: Arc::new(Mutex::new(HashMap::new())),
        }
    }
}

/// Simple glob matching: `*` matches any sequence of characters.
fn glob_matches(pattern: &str, text: &str) -> bool {
    if pattern == "*" {
        return true;

View on GitHub (pinned to 88bb9c8533)

Solutions

  1. Disconnect the ACP clients using that agent (close the editor/TUI windows or tabs holding the session), then re-run `zeroclaw agents delete <alias>`
  2. If no client is visibly connected, stop the running zeroclaw gateway process (it owns the `/acp` WebSocket sessions), then retry the delete
  3. For scripted deletes, always stop or drain the gateway first so no `/acp` sessions can be live
  4. If it still refuses, inspect the ACP session store under data_dir for live rows owned by the alias and report stale rows as a bug rather than deleting state by hand

Example fix

# before
$ zeroclaw agents delete writer
Error: 2 live ACP session(s) for `writer` — end them first

# after
$ # 1. close the ACP clients (editor/TUI) using that agent
$ # 2. stop the zeroclaw gateway (it owns the /acp WebSocket sessions)
$ zeroclaw agents delete writer
Defensive patterns

Strategy: validation

Validate before calling

use zeroclaw_gateway::agent_owned_state::live_acp_session_count;

// Run the same gate the CLI precheck uses BEFORE attempting the delete.
fn agent_safe_to_delete(config: &Config, alias: &str) -> anyhow::Result<bool> {
    Ok(live_acp_session_count(config, alias)? == 0)
}

Try / catch

match alias_delete(&config, &alias).await {
    Err(e) if e.to_string().contains("live ACP session(s)") => {
        // Refusal, not a crash: surface it, have the operator close ACP
        // clients / stop the gateway, then retry. Never delete session
        // state by hand to force the delete through.
    }
    other => other,
}

Prevention

When it happens

Trigger: Running `zeroclaw agents delete <alias>` (after confirming/--yes) while an ACP client — an editor or TUI integration — holds an open `/acp` WebSocket session attributed to that alias, typically with the zeroclaw gateway running. Any state where count_live_sessions_by_agent(alias) returns > 0, including session rows not yet marked ended after an abrupt client exit while the gateway is still up.

Common situations: Deleting an agent from one terminal while an editor integration still has the agent's session open in another; automated cleanup scripts that run against a live gateway with connected ACP clients; stale live-session rows after a crashed client when the gateway process is still alive.

Related errors


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