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
- Wrap the value in an array: `coordination_contracts = ["ledger"]` in TOML or `["ledger"]` in JSON.
- If the generator emits this field, fix it to always serialize a list of strings.
- 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
- Serialize coordination_contracts from Vec<String> so the shape is always a JSON array.
- In TOML, use bracket list syntax: coordination_contracts = ["ledger"].
- Prefer omitting the key over writing a placeholder scalar.
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
- fleet task '{}' coordination contracts must be one non-empty
- fleet task '{}' metadata.coordination_contracts accepts at m
- fleet task '{}' metadata.coordination_contracts must contain
- fleet task {task_id} has duplicate tag {tag}
- fleet task {} environment variable name cannot be empty
AI-assisted analysis of Hmbown/CodeWhale@0c42157ee5 (2026-08-20).
Data as JSON: /api/errors/4f98dadc4fb57579.
Report an issue: GitHub.