Hmbown/CodeWhale · error · anyhow::Error

Tool Web is limited to search/fetch in the read-only…

Error message

Tool Web is limited to search/fetch in the read-only evidence profile

What it means

In the read-only evidence profile, Scout and Reviewer roles may use the Web tool only with `action` = `search` or `fetch`. Any other Web action is rejected, because catalog shaping alone is not authority — the per-action gate is re-checked at dispatch to stop hand-written calls from reaching restricted actions.

Solutions

  1. Restrict the Web call to `action: "search"` or `action: "fetch"`.
  2. If a non-read action is genuinely required, delegate to a role with write authority (implement/general).
  3. Check the action string for typos or unsupported verbs.
  4. Update the orchestrating instructions to state read-only web constraints up front.

Example fix

// before
Web.call({ action: "post", url: "https://api.example.com" })
// after
Web.call({ action: "fetch", url: "https://api.example.com" })
Defensive patterns

Strategy: validation

Validate before calling

if ((role === 'scout' || role === 'reviewer') && toolName === 'Web' &&
    !['search','fetch'].includes(input.action)) {
  throw new Error('web action not allowed in read-only profile');
}

Type guard

const isReadOnlyWebAction = (a) => a === 'search' || a === 'fetch';

Try / catch

try { web.call(input); } catch (e) { if (String(e).includes('search/fetch')) { input.action = 'fetch'; retry(); } }

Prevention

When it happens

Trigger: A Scout or Reviewer sub-agent calls the Web tool with an action other than search/fetch (e.g. `post`, `download`, `submit`) — whether from the model improvising or from a hand-constructed tool call.

Common situations: A child attempts to submit a form or authenticate to a site while doing research; a parent with full web access had its task delegated to a read-only child that tries the same Web verbs; action name typo causes a match failure.

Understand the failure class

Background: Permission denied / not authorized / 403 Forbidden: access-control rejections when the caller lacks the required role, grant, or ownership — this error's family across 18 libraries.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@433685b202 (2026-09-15). Data as JSON: /api/errors/fe543803de2afa1e. Report an issue: GitHub.

Appendix: source

Thrown at crates/tui/src/tools/subagent/mod.rs:17492

    async fn execute_full(
        &self,
        agent_id: &str,
        tool_id: &str,
        name: &str,
        input: Value,
    ) -> Result<RichToolResult> {
        if self.role_blocks_unhardened_process_tool(name) {
            return Err(anyhow!(
                "Tool {name} is not available to this read-only worker because its process path does not share the hardened evidence boundary. Use read/search, classifier-bounded bash reads, or the verifier's bounded Run tool instead."
            ));
        }
        let action = input.get("action").and_then(Value::as_str);
        if matches!(&self.agent_type, FleetRole::Scout | FleetRole::Reviewer)
            && name == "Web"
            && !matches!(action, Some("search" | "fetch"))
        {
            return Err(anyhow!(
                "Tool Web is limited to search/fetch in the read-only evidence profile"
            ));
        }
        // Catalog shaping is not authority. `agent` clears both name-keyed
        // gates below by design, so the per-action gate has to be repeated
        // here or a hand-written call would reach an action the role's own
        // catalog withheld.
        if name == "agent"
            && matches!(parse_agent_tool_action(&input), Ok(AgentToolAction::Claim))
            && !self.agent_action_permitted("claim")
        {
            return Err(anyhow!(
                "agent action=claim widens an enforced write scope, and the Fleet role `{role}` has no write authority to widen. Use an `implement` or `general` role.",
                role = self.agent_type.as_str()
            ));
        }
        let family_action_allowed = if !Self::ACTION_ALIASES
            .iter()

View on GitHub (pinned to 433685b202)