{"record":{"id":"21dc63322d0bdf25","repo":"Hmbown/CodeWhale","slug":"fleet-task-metadata-coordination-contracts-must-be-an-array","errorCode":null,"errorMessage":"Fleet task '{}' metadata.coordination_contracts must be an array of strings","messagePattern":"Fleet task '(.+?)' metadata\\.coordination_contracts must be an array of strings","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/tui/src/fleet/worker_runtime.rs","lineNumber":592,"sourceCode":"                    path.display()\n                );\n            }\n            value => segments.push(value),\n        }\n    }\n    Ok(if segments.is_empty() {\n        \".\".to_string()\n    } else {\n        segments.join(\"/\")\n    })\n}\n\nfn fleet_coordination_contracts(task_spec: &FleetTaskSpec) -> Result<Vec<String>> {\n    let Some(value) = task_spec.metadata.get(\"coordination_contracts\") else {\n        return Ok(Vec::new());\n    };\n    let Some(values) = value.as_array() else {\n        bail!(\n            \"Fleet task '{}' metadata.coordination_contracts must be an array of strings\",\n            task_spec.id\n        );\n    };\n    if values.len() > 16 {\n        bail!(\n            \"Fleet task '{}' metadata.coordination_contracts accepts at most 16 entries\",\n            task_spec.id\n        );\n    }\n    let mut contracts = Vec::new();\n    for value in values {\n        let Some(value) = value.as_str() else {\n            bail!(\n                \"Fleet task '{}' metadata.coordination_contracts must contain only strings\",\n                task_spec.id\n            );\n        };","sourceCodeStart":574,"sourceCodeEnd":610,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/tui/src/fleet/worker_runtime.rs#L574-L610","documentation":"fleet_coordination_contracts reads task_spec.metadata[\"coordination_contracts\"]; when the key exists but its value is not a JSON array, the task cannot form a coordination claim and the spec build fails. Contracts must be an array of strings (bounded at 16 entries).","triggerScenarios":"fleet_task_to_worker_spec_with_profiles -> fleet_coordination_contracts where metadata contains `coordination_contracts` as a string (e.g. `\"contract-a\"`), object, or number instead of an array.","commonSituations":"Hand-editing fleet run JSON and writing the contract as a single string instead of a one-element array; YAML/JSON type confusion where a quoted string was intended as a list; programmatic metadata writers storing the field under the wrong shape.","solutions":["Wrap the value in an array: `\"coordination_contracts\": [\"contract-a\"]`.","Remove the metadata key entirely if no contracts are needed (missing key is valid and returns an empty vec).","Fix the metadata producer to emit a JSON array of strings.","Validate run JSON before submission so malformed metadata is caught early."],"exampleFix":"// before\n\"metadata\": { \"coordination_contracts\": \"lease:db-migration\" }\n\n// after\n\"metadata\": { \"coordination_contracts\": [\"lease:db-migration\"] }","handlingStrategy":"type-guard","validationCode":"const contracts = run.metadata?.coordination_contracts;\nif (contracts !== undefined && !Array.isArray(contracts)) throw new Error(\"coordination_contracts must be an array\");","typeGuard":"function isStringArray(v) { return Array.isArray(v) && v.every(x => typeof x === \"string\"); }","tryCatchPattern":"try { build_spec(task) } catch (e) { if (String(e).includes(\"must be an array of strings\")) { fix_metadata_shape(task); } else { throw e; } }","preventionTips":["Emit coordination_contracts only as arrays of strings.","Omit the key entirely when there are no contracts.","Schema-validate run JSON before creating the run."],"tags":["fleet","metadata","schema","validation"],"backgroundTag":"schema-validation-failed","analyzedSha":"73e0f67d83c59909b571efdfc88c4bc28c309cb1","analyzedAt":"2026-09-22T01:30:00.501Z","contentChangedAt":"2026-09-22T01:30:00.501Z","schemaVersion":2},"datasetVersion":"2026-09-22T11:17:16.035Z"}