Hmbown/CodeWhale · error

deliverable is outside the worker write scope; declare an…

Error message

deliverable {path:?} is outside the worker write scope; declare an exact_files entry or a containing write_roots path

What it means

Each declared deliverable path must fall inside the worker's write scope. If the agent is write-capable, the spawn validates every deliverable against its write_claim (exact_files or write_roots); a deliverable that is neither covered by an exact_files entry nor contained in a write_roots path is rejected. This prevents workers from being asked to produce files they are not authorized to write.

Solutions

  1. Add the deliverable's exact path to the write_claim's exact_files list.
  2. Or add/extend a write_roots entry so it contains (is a parent directory of) the deliverable path.
  3. Verify path forms match: both the deliverable and the claim must resolve against the same workspace root; fix absolute-vs-relative mismatches.

Example fix

// before
write_claim: WriteClaim { write_roots: vec!["src/".into()], exact_files: vec![] },
deliverables: vec!["src/report.md".into(), "tests/report_test.rs".into()]
// after
write_claim: WriteClaim {
    write_roots: vec!["src/".into()],
    exact_files: vec!["tests/report_test.rs".into()],
},
deliverables: vec!["src/report.md".into(), "tests/report_test.rs".into()]
Defensive patterns

Strategy: validation

Validate before calling

function deliverablesInScope(deliverables, claim) {
  return deliverables.every(p =>
    claim.exactFiles.includes(p) || claim.writeRoots.some(root => p.startsWith(root)));
}

Type guard

const isCovered = (p, claim) =>
  claim.exact_files.includes(p) || claim.write_roots.some(r => p === r || p.startsWith(r.trim_end_matches('/') + '/'));

Try / catch

match spawn_result {
    Err(e) if e.to_string().contains("outside the worker write scope") => fix_write_claim_and_retry(),
    other => other?,
}

Prevention

When it happens

Trigger: Spawning a write-capable sub-agent whose `deliverables` list includes a path outside the paths granted by options.write_claim (write_claim.contains_path returns false for it, or write_claim is None).

Common situations: Deliverables declared as bare file names or absolute paths while write_roots use relative workspace paths; adding a new deliverable after tightening the write claim; forgetting to declare the deliverable in exact_files at all.

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@73e0f67d83 (2026-09-22). Data as JSON: /api/errors/9baecfbc0b99890d. Report an issue: GitHub.

Appendix: source

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

        let delivery_paths =
            delivery::declared_paths(&options.deliverables, options.expected_artifact.as_deref())
                .map_err(anyhow::Error::msg)?;
        for path in &delivery_paths {
            delivery::safe_deliverable_path(&agent.workspace, path).map_err(anyhow::Error::msg)?;
            let claimed_path = if options.claim_pre_namespaced && !options.isolated_worktree {
                let prefix = coordination_workspace_prefix(&self.workspace, &agent.workspace)
                    .map_err(anyhow::Error::msg)?;
                namespace_coordination_path(&prefix, path).map_err(anyhow::Error::msg)?
            } else {
                path.clone()
            };
            if !write_capable
                || !options
                    .write_claim
                    .as_ref()
                    .is_some_and(|claim| claim.contains_path(&claimed_path))
            {
                return Err(anyhow!(
                    "deliverable {path:?} is outside the worker write scope; declare an exact_files entry or a containing write_roots path"
                ));
            }
        }
        if write_capable {
            // Isolated-worktree children mutate their own checkout, so they
            // do not contend for the shared-workspace process lock (#5036).
            if !options.isolated_worktree {
                self.ensure_coordination_process_lock()
                    .map_err(anyhow::Error::msg)?;
            }
            if self.coordination_process_lock_required && self.state_path.is_none() {
                return Err(anyhow!(
                    "write-capable sub-agent launch requires a durable coordination state path"
                ));
            }
        }
        let durable_registration = write_capable || continuation_from.is_some();

View on GitHub (pinned to 73e0f67d83)