Hmbown/CodeWhale · error · anyhow::Error
Fleet authority fingerprint
Error message
Fleet authority fingerprint `{expected}` is not a form this build understands; refusing the spawn rather than launching an unverified child What it means
verify_fleet_authority_input parses a Fleet authority fingerprint string of the form "v1;key=value;..." and requires at least 8 key=value fields. If the fingerprint does not start with "v1;" or has fewer than 8 fields, the build refuses to spawn the child agent rather than launching it with an unverifiable authority receipt. This is a fail-loud guard against forged or malformed authority data.
Solutions
- Regenerate the Fleet authority fingerprint with the current build so it uses the supported v1 format with all 8+ fields
- Verify the full fingerprint string was copied — check for truncation (missing trailing fields)
- Check that both parent and child tooling are the same version and share one fingerprint format
- Do not hand-edit the fingerprint; re-issue it through the fleet authority issuance path
Example fix
// before: truncated receipt let fp = "v1;depth=2;allow=read"; // after: full v1 receipt with all required fields let fp = "v1;depth=2;allow=read;deny=write;budget=...;model=...;scope=...;issuer=...;ts=...";
Defensive patterns
Strategy: validation
Validate before calling
fn is_supported_fingerprint(fp: &str) -> bool {
fp.starts_with("v1;") && fp.split(';').filter(|p| p.contains('=')).count() >= 8
} Try / catch
match spawn_child(&fp, &input) {
Err(e) if e.to_string().contains("not a form this build understands") => {
let fp = reissue_fingerprint(); // regenerate with current build
spawn_child(&fp, &input)
}
other => other,
} Prevention
- Never hand-edit authority fingerprints; re-issue them
- Keep parent and child tooling on the same version
- Validate the fingerprint format at receipt storage time, not just spawn time
When it happens
Trigger: Spawning a sub-agent whose fleet authority fingerprint string is from an older/other version (missing v1 prefix), was truncated in transit or storage, or was hand-edited so fewer than 8 fields remain.
Common situations: Mixing builds where one writes a newer fingerprint format the other cannot parse, copy-paste truncation of the receipt in config, or a stale persisted authority token from a previous release.
Understand the failure class
Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.
Related errors
- Fleet authority mismatch at the spawn boundary: the receipt…
- agent profile cannot be empty
- agent profile must be a simple token
- agent profile model must be a visible model id without…
- agent profile provider cannot be empty
AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22).
Data as JSON: /api/errors/b85116e393ef8a2b.
Report an issue: GitHub.
Appendix: source
Thrown at crates/tui/src/tools/subagent/mod.rs:11003
/// The fingerprint is produced by `ChildAuthority::fingerprint` and names every
/// field of the envelope. Only four of them survive into the spawn input as
/// distinct keys — `write_authority`, `max_depth`, `allowed_tools`,
/// `disallowed_tools` — and those are exactly the four this function can and
/// does verify. The remaining fields (`tools`, `network`, `shell`, `posture`)
/// are *derivations* the Fleet used to compute those four, so a divergence in
/// any of them shows up in one of the four; verifying the wire form is
/// therefore the stronger check, not the weaker one, because it is the value
/// the child is actually constructed from.
///
/// Fails closed in every ambiguous case: an unparseable fingerprint is a
/// refusal, not a pass.
fn verify_fleet_authority_input(expected: &str, input: &Value) -> Result<()> {
let fields: std::collections::HashMap<&str, &str> = expected
.split(';')
.filter_map(|part| part.split_once('='))
.collect();
if !expected.starts_with("v1;") || fields.len() < 8 {
return Err(anyhow!(
"Fleet authority fingerprint `{expected}` is not a form this build understands; \
refusing the spawn rather than launching an unverified child"
));
}
let listed = |key: &str| -> String {
let mut values: Vec<String> = input
.get(key)
.and_then(Value::as_array)
.map(|items| {
items
.iter()
.filter_map(Value::as_str)
.map(str::to_string)
.collect()
})
.unwrap_or_default();
values.sort();View on GitHub (pinned to 73e0f67d83)