Hmbown/CodeWhale · error
fleet authority mismatch at the spawn boundary: the receipt
Error message
fleet authority mismatch at the spawn boundary: the receipt names {key}=`{expected_value}` but the child would be constructed with `{actual}`. Refusing the spawn — a Fleet ceiling that does not reach the runtime is not a ceiling. What it means
At the spawn boundary, `verify_fleet_authority_input` compares the actual spawn input just built against the receipt's fingerprint for four fields: write (write ceiling), depth (max_depth), allow (allowed_tools list), deny (disallowed_tools list). A mismatch means the receipt authorizes a different child surface than the one about to launch, so the spawn fails closed (mapped to ToolError::permission_denied). The wire form is the source of truth because it is what the child is actually constructed from.
Source
Thrown at crates/tui/src/tools/subagent/mod.rs:9635
let actual_write = input
.get("write_authority")
.and_then(Value::as_str)
.unwrap_or("read_only");
let actual_depth = input
.get("max_depth")
.and_then(Value::as_u64)
.map(|depth| depth.to_string())
.unwrap_or_default();
for (key, actual) in [
("write", actual_write.to_string()),
("depth", actual_depth),
("allow", actual_allow),
("deny", listed("disallowed_tools")),
] {
let expected_value = fields.get(key).copied().unwrap_or_default();
if expected_value != actual {
return Err(anyhow!(
"fleet authority mismatch at the spawn boundary: the receipt names {key}=`{expected_value}` \
but the child would be constructed with `{actual}`. Refusing the spawn — a Fleet \
ceiling that does not reach the runtime is not a ceiling."
));
}
}
Ok(())
}
// === Sub-agent Execution ===
/// Build the system prompt for a sub-agent.
///
/// Starts with the per-type prompt (`FleetRole::system_prompt`) and
/// appends a one-line role overlay when `assignment.role` is set. The
/// full role library — TOML overlays from `~/.deepseek/roles/`, the
/// `/roles` slash command, model overrides per role — lands in 0.6.7.
/// For 0.6.6 we just don't drop the role on the floor: the model seesView on GitHub (pinned to 0c42157ee5)
Solutions
- Re-issue the receipt (re-run the Fleet/workflow step that mints it) after any policy or option change, so the fingerprint matches the current spawn input.
- Diff the four fields named by the error (write, depth, allow, deny) to find which one the spawn added, dropped, or reordered.
- Do not mutate allowed_tools/disallowed_tools/max_depth between receipt creation and spawn_workflow_task.
- Never reuse persisted receipts across builds whose defaults changed — regenerate them.
Example fix
// before: receipt minted, then tools mutated before spawn
request.allowed_tools = Some(vec!["read".into()]); // diverges from receipt
spawn_workflow_task(identity, request).await?; // permission_denied (Err 1218)
// after: mint receipt from the same request you spawn with
let receipt = authority.fingerprint_for(&request);
let identity = Identity { fleet_authority_fingerprint: Some(receipt), .. };
spawn_workflow_task(identity, request).await?; Defensive patterns
Strategy: try-catch
Validate before calling
// Re-run the same comparison before spawn to fail with a clear diagnostic:
if let Some(expected) = identity.fleet_authority_fingerprint.as_deref() {
verify_fleet_authority_input(expected, &input)
.context("receipt/spawn divergence — re-issue the receipt after policy changes")?;
} Type guard
fn spawn_matches_receipt(expected: &str, input: &serde_json::Value) -> bool {
verify_fleet_authority_input(expected, input).is_ok()
} Try / catch
match spawn_workflow_task(identity, request).await {
Err(ToolError::PermissionDenied(msg)) if msg.contains("fleet authority mismatch") => {
// fail-closed spawn: diff write/depth/allow/deny vs the receipt, re-mint, retry once
}
r => r?,
} Prevention
- Mint the receipt from the exact request object you will spawn with.
- Never mutate allowed_tools/disallowed_tools/max_depth between minting and spawn.
- Re-issue receipts after any Fleet policy edit or build upgrade.
- Never bypass or strip the fingerprint to make a spawn pass.
When it happens
Trigger: spawn_workflow_task where request.allowed_tools / disallowed_tools / max_depth / write flag diverge from the receipt: policy edited after the receipt was minted, defaults applied between minting and spawn, or host-derived ceilings (e.g. network_tool=false) converted to deny lists the receipt didn't name.
Common situations: Editing a Fleet's allow/deny lists after issuing receipts; replaying old receipts against a build with new defaults; code paths that add or filter tools between receipt creation and spawn; stale identity records attached to retried tasks.
Related errors
- fleet authority fingerprint `{expected}` is not a form this
- Refusing to interrupt root. agents/interrupt fails closed on
- Refusing {action} on self (agent_id '{agent_id}'); child coo
- Refusing {action} from agent '{caller}' to '{agent_id}'; a c
- external {} credential file {} exceeds the {} byte safety li
AI-assisted analysis of Hmbown/CodeWhale@0c42157ee5 (2026-08-20).
Data as JSON: /api/errors/f6f318148d9ca46b.
Report an issue: GitHub.