Hmbown/CodeWhale · error

validated Fleet tool authority envelope must serialize

Error message

validated Fleet tool authority envelope must serialize

What it means

Panic while spawning a Fleet worker: the tool authority envelope (a `Serialize` struct) is stringified to pass as `--tool-authority-json` to the `codewhale exec` child process. The message records the upstream assumption that the envelope was validated. `serde_json::to_string` fails when any field cannot appear in JSON: map keys that are not strings, or non-finite floats.

Source

Thrown at crates/tui/src/fleet/executor.rs:271

    }
    if !exec_config.disallowed_tools.is_empty() {
        args.push("--disallowed-tools".to_string());
        args.push(exec_config.disallowed_tools.join(","));
    }
    if exec_config.max_turns > 0 {
        args.push("--max-turns".to_string());
        args.push(exec_config.max_turns.to_string());
    }
    if !exec_config.append_system_prompt.trim().is_empty() {
        args.push("--append-system-prompt".to_string());
        args.push(exec_config.append_system_prompt.clone());
    }

    if let Some(authority) = authority {
        args.push("--tool-authority-json".to_string());
        args.push(
            serde_json::to_string(authority)
                .expect("validated Fleet tool authority envelope must serialize"),
        );
    }

    // The composed task prompt is the final positional argument.
    args.push(task_prompt);

    FleetWorkerCommand::new(codewhale_binary.to_string(), args)
}

/// Map one `codewhale exec` stream-json line into a fleet ledger event.
///
/// Returns `None` for lines that don't correspond to a worker lifecycle
/// transition (e.g. `session_capture`, `metadata`). The exec event schema is
/// `{"type": "...", ...}` (see `ExecStreamEvent` in `main.rs`).
pub fn map_exec_stream_line(line: &str) -> Option<FleetWorkerEventPayload> {
    let value: serde_json::Value = serde_json::from_str(line.trim()).ok()?;
    match value.get("type").and_then(serde_json::Value::as_str)? {
        "tool_use" => {

View on GitHub (pinned to 0c42157ee5)

Solutions

  1. Identify the recently added field and change it to a string-keyed map (`BTreeMap<String, _>`) or a sanitized number; rebuild.
  2. Convert the expect into `serde_json::to_string(authority).context(...)?` so a spawn failure carries an actionable error.
  3. Add a round-trip unit test: `serde_json::to_value(&sample_authority()).unwrap()`.
  4. Audit sibling CLI argument structs for the same key-type hazard.

Example fix

// before
serde_json::to_string(authority).expect("validated Fleet tool authority envelope must serialize")

// after: fail the worker spawn with an actionable error
let authority_json = serde_json::to_string(authority)
    .with_context(|| "serialize tool authority envelope for fleet worker spawn")?;
Defensive patterns

Strategy: validation

Validate before calling

// Prove the envelope stringifies before spawning the worker
if serde_json::to_string(authority).is_err() {
    return Err(anyhow!("tool authority envelope contains non-JSON-representable fields"));
}

Prevention

When it happens

Trigger: Extending the authority envelope with a `HashMap<u32, _>`-style non-string-keyed map, or an f64 field that received `NaN`/`Infinity` from a config computation; the first fleet run after that change panics while assembling spawn args, before any worker starts.

Common situations: Version skew between the fleet executor struct and newly added authority fields; copying a config struct with non-JSON-friendly key types into the envelope; NaN leaking from default-on-missing arithmetic in config merging.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@0c42157ee5 (2026-08-20). Data as JSON: /api/errors/95f5bf4e6e027858. Report an issue: GitHub.