Hmbown/CodeWhale · error

fleet task '{}' metadata.coordination_contracts must be an a

Error message

fleet task '{}' metadata.coordination_contracts must be an array of strings

What it means

The task's `metadata.coordination_contracts` value exists but is not an array — `fleet_coordination_contracts` requires `serde_json::Value::Array`. In TOML task files, metadata fields deserialize into JSON values, so a bare string, number, or inline table fails this check. Coordination contracts are how write-capable tasks declare their coordination surface when they do not use writable_paths.

Source

Thrown at crates/tui/src/fleet/worker_runtime.rs:383

                    path.display()
                );
            }
            value => segments.push(value),
        }
    }
    Ok(if segments.is_empty() {
        ".".to_string()
    } else {
        segments.join("/")
    })
}

fn fleet_coordination_contracts(task_spec: &FleetTaskSpec) -> Result<Vec<String>> {
    let Some(value) = task_spec.metadata.get("coordination_contracts") else {
        return Ok(Vec::new());
    };
    let Some(values) = value.as_array() else {
        bail!(
            "fleet task '{}' metadata.coordination_contracts must be an array of strings",
            task_spec.id
        );
    };
    if values.len() > 16 {
        bail!(
            "fleet task '{}' metadata.coordination_contracts accepts at most 16 entries",
            task_spec.id
        );
    }
    let mut contracts = Vec::new();
    for value in values {
        let Some(value) = value.as_str() else {
            bail!(
                "fleet task '{}' metadata.coordination_contracts must contain only strings",
                task_spec.id
            );
        };

View on GitHub (pinned to 0c42157ee5)

Solutions

  1. Wrap the value in an array: `coordination_contracts = ["ledger"]` in TOML or `["ledger"]` in JSON.
  2. If the generator emits this field, fix it to always serialize a list of strings.
  3. Remove the key entirely if the task uses writable_paths and needs no contracts.

Example fix

# before
[metadata]
coordination_contracts = "ledger"

# after
[metadata]
coordination_contracts = ["ledger"]
Defensive patterns

Strategy: validation

Validate before calling

fn contracts_well_typed(metadata: &std::collections::BTreeMap<String, serde_json::Value>) -> bool {
    match metadata.get("coordination_contracts") {
        None => true,
        Some(serde_json::Value::Array(_)) => true,
        Some(_) => false,
    }
}

Type guard

fn is_contract_array(value: &serde_json::Value) -> bool {
    matches!(value, serde_json::Value::Array(_))
}

Prevention

When it happens

Trigger: `coordination_contracts = "ledger"` (plain string) or `= 3` or an inline table under `[metadata]`; a JSON spec with `"coordination_contracts": {"name": "ledger"}`.

Common situations: Authors writing a single contract as a scalar instead of a one-element list; generators emitting the wrong JSON type; upgrading an old spec format that allowed a string.

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.

Related errors


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