{"record":{"id":"c00e591c8ac00fd1","repo":"Hmbown/CodeWhale","slug":"fleet-authority-fingerprint-expected-is-not-a","errorCode":null,"errorMessage":"fleet authority fingerprint `{expected}` is not a form this build understands; refusing the spawn rather than launching an unverified child","messagePattern":"fleet authority fingerprint `(.+?)` is not a form this build understands; refusing the spawn rather than launching an unverified child","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/tui/src/tools/subagent/mod.rs","lineNumber":9589,"sourceCode":"/// The fingerprint is produced by `ChildAuthority::fingerprint` and names every\n/// field of the envelope. Only four of them survive into the spawn input as\n/// distinct keys — `write_authority`, `max_depth`, `allowed_tools`,\n/// `disallowed_tools` — and those are exactly the four this function can and\n/// does verify. The remaining fields (`tools`, `network`, `shell`, `posture`)\n/// are *derivations* the Fleet used to compute those four, so a divergence in\n/// any of them shows up in one of the four; verifying the wire form is\n/// therefore the stronger check, not the weaker one, because it is the value\n/// the child is actually constructed from.\n///\n/// Fails closed in every ambiguous case: an unparseable fingerprint is a\n/// refusal, not a pass.\nfn verify_fleet_authority_input(expected: &str, input: &Value) -> Result<()> {\n    let fields: std::collections::HashMap<&str, &str> = expected\n        .split(';')\n        .filter_map(|part| part.split_once('='))\n        .collect();\n    if !expected.starts_with(\"v1;\") || fields.len() < 8 {\n        return Err(anyhow!(\n            \"fleet authority fingerprint `{expected}` is not a form this build understands; \\\n             refusing the spawn rather than launching an unverified child\"\n        ));\n    }\n\n    let listed = |key: &str| -> String {\n        let mut values: Vec<String> = input\n            .get(key)\n            .and_then(Value::as_array)\n            .map(|items| {\n                items\n                    .iter()\n                    .filter_map(Value::as_str)\n                    .map(str::to_string)\n                    .collect()\n            })\n            .unwrap_or_default();\n        values.sort();","sourceCodeStart":9571,"sourceCodeEnd":9607,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/0c42157ee52f9d55af2b506d71b46249910f77d3/crates/tui/src/tools/subagent/mod.rs#L9571-L9607","documentation":"`verify_fleet_authority_input` parses the expected Fleet authority fingerprint by splitting on ';' into key=value fields; it must start with \"v1;\" and yield at least 8 fields. Anything else — a stale format from another build, a truncated string, a hand-built fingerprint — is an unparseable receipt and the spawn is refused rather than launching an unverified child (fail closed).","triggerScenarios":"spawn_workflow_task with identity.fleet_authority_fingerprint that doesn't start with \"v1;\" or has fewer than 8 segments: receipts persisted by an older/newer version and replayed, a fingerprint truncated in storage or transit, or one assembled by string concatenation instead of the authority's fingerprint() method.","commonSituations":"Version skew between the component minting receipts and the one verifying; reusing persisted receipts after an upgrade; typo'd fingerprint configuration; hand-rolled fingerprint construction in extensions.","solutions":["Regenerate the workflow/task receipt with the current build so the fingerprint is re-minted in v1 format.","Check the fingerprint string starts with \"v1;\" and contains at least 8 key=value segments separated by ';'.","Align the receipt-minting component and the verifying build to the same version; don't mix them.","If you construct fingerprints programmatically, call the authority's fingerprint() method — never build the string by hand."],"exampleFix":"// before: hand-built fingerprint\nlet fp = format!(\"write={};depth={}\", w, d); // not v1; ... -> Err 1217\n\n// after: use the authority's own minting\nlet fp = authority.fingerprint(); // \"v1;write=...;depth=...;allow=...;deny=...\" (8+ fields)","handlingStrategy":"validation","validationCode":"fn fingerprint_is_parseable(expected: &str) -> bool {\n    let fields: Vec<_> = expected.split(';').filter_map(|p| p.split_once('=')).collect();\n    expected.starts_with(\"v1;\") && fields.len() >= 8\n}\n// before spawn: if !fingerprint_is_parseable(fp) { re-mint the receipt }","typeGuard":"fn is_v1_fingerprint(expected: &str) -> bool {\n    fingerprint_is_parseable(expected)\n}","tryCatchPattern":"match verify_fleet_authority_input(expected, &input) {\n    Err(e) if e.to_string().contains(\"not a form this build understands\") => {\n        // stale/malformed receipt: do NOT strip the fingerprint; re-mint it with the current build\n    }\n    r => r?,\n}","preventionTips":["Mint fingerprints only via the authority's fingerprint() method.","Regenerate persisted receipts after upgrades; never hand-edit them.","Keep the receipt-minting and verifying components on the same version."],"tags":["subagent","fleet","fingerprint","authorization","rust"],"backgroundTag":"fingerprint-format-invalid","analyzedSha":"0c42157ee52f9d55af2b506d71b46249910f77d3","analyzedAt":"2026-08-20T21:50:45.477Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}