{"record":{"id":"340368571e990dbe","repo":"Hmbown/CodeWhale","slug":"fleet-task-metadata-coordination-contracts-must-contain-only","errorCode":null,"errorMessage":"Fleet task '{}' metadata.coordination_contracts must contain only strings","messagePattern":"Fleet task '(.+?)' metadata\\.coordination_contracts must contain only strings","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/tui/src/fleet/worker_runtime.rs","lineNumber":606,"sourceCode":"    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        };\n        let value = value.trim();\n        if value.is_empty()\n            || value.chars().count() > 128\n            || value.chars().any(|ch| matches!(ch, '\\0' | '\\r' | '\\n'))\n        {\n            bail!(\n                \"Fleet task '{}' coordination contracts must be one non-empty line of at most 128 characters\",\n                task_spec.id\n            );\n        }\n        if !contracts.iter().any(|contract| contract == value) {\n            contracts.push(value.to_string());\n        }\n    }","sourceCodeStart":588,"sourceCodeEnd":624,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/tui/src/fleet/worker_runtime.rs#L588-L624","documentation":"Each entry of metadata.coordination_contracts must be a JSON string. fleet_coordination_contracts walks the array and fails the task if any element is a non-string (object, number, boolean, null), since contracts are identifier-like strings consumed by the coordination manager.","triggerScenarios":"fleet_task_to_worker_spec_with_profiles -> fleet_coordination_contracts where the array contains a non-string element, e.g. `\"coordination_contracts\": [\"lease:db\", 42]` or nested objects describing contracts.","commonSituations":"Generated metadata serializing contract objects instead of their names; mixed-type arrays from loosely typed config formats; copying contract definitions from another tool that used structured entries.","solutions":["Replace non-string entries with their string identifiers.","If contracts were structured objects, extract the identifying field (e.g. `.name`) into a plain string.","Fix the metadata generator's serializer to emit strings only.","Trim/validate each entry after conversion — empty strings after trim are also rejected downstream."],"exampleFix":"// before\n\"coordination_contracts\": [\"lease:db\", {\"name\": \"lock:idx\"}]\n\n// after\n\"coordination_contracts\": [\"lease:db\", \"lock:idx\"]","handlingStrategy":"type-guard","validationCode":"if (!contracts.every(c => typeof c === \"string\" && c.trim() !== \"\")) throw new Error(\"coordination_contracts must contain only non-empty strings\");","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 contain only strings\")) { coerce_contracts_to_strings(task); } else { throw e; } }","preventionTips":["Serialize contract entries as plain strings, not objects.","Coerce/extract identifiers from structured contracts at generation time.","Validate array element types before run creation."],"tags":["fleet","metadata","type-mismatch","validation"],"backgroundTag":"type-mismatch","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"}