Hmbown/CodeWhale · error · anyhow::Error

agent action=claim widens an enforced write scope, and the…

Error message

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.

What it means

`agent action=claim` widens an enforced write scope (claiming work items). A Fleet role without write authority cannot widen any scope, so when the action gate `agent_action_permitted("claim")` fails, the dispatch layer rejects the call before it runs, independent of what the role's catalog withheld.

Solutions

  1. Re-spawn the worker with an `implement` or `general` role that has write authority.
  2. Have the read-only worker request the claim through the parent agent instead of calling `agent action=claim` itself.
  3. Verify the input action field actually means claim (check `ACTION_ALIASES`) and correct it if the worker intended a different action.
  4. Grant claim permission to the role in fleet configuration if this is an intended workflow change.

Example fix

// before
// scout role:
Agent.call({ action: "claim", task_id: 42 })
// after
// delegate to implement role or ask parent to claim:
Agent.call({ action: "claim", task_id: 42 }) // run by an 'implement' role
Defensive patterns

Strategy: validation

Validate before calling

const action = parseAgentAction(input);
if (action === 'claim' && !roleCanWrite(agentType)) {
  throw new Error('claim requires implement/general role');
}

Type guard

const hasWriteAuthority = (role) => ['implement','general'].includes(role);

Try / catch

try { agent.call(input); } catch (e) { if (String(e).includes('no write authority to widen')) { parentClaim(taskId); } }

Prevention

When it happens

Trigger: A sub-agent whose `agent_type` lacks write authority (e.g. scout, reviewer) issues `agent` with `action=claim`, and `parse_agent_tool_action` resolves it to `AgentToolAction::Claim` while `agent_action_permitted("claim")` returns false.

Common situations: A read-only worker tries to claim a work-graph item; the prompt template includes claim instructions written for implement roles; action alias parsing maps an ambiguous input onto `claim`.

Understand the failure class

Background: "You do not have permission" / 403 Forbidden errors: authenticated but not allowed — causes and fixes across open-source libraries — this error's family across 31 libraries.

Related errors


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

Appendix: source

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

        }
        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()
            .any(|(family, _, _)| *family == name)
        {
            true
        } else if let Some(action) = action {
            self.is_action_allowed(name, action)
        } else {
            self.allowed_tools
                .as_ref()
                .is_none_or(|list| list.iter().any(|allowed| allowed == name))
        };
        if !self.is_tool_allowed(name) || !family_action_allowed {
            return Err(anyhow!("Tool {name} not allowed for this sub-agent"));

View on GitHub (pinned to 433685b202)