{"record":{"id":"4eb6942f81728445","repo":"affaan-m/ECC","slug":"conflict-messages-require-at-least-one-file","errorCode":null,"errorMessage":"Conflict messages require at least one --file","messagePattern":"Conflict messages require at least one --file","errorType":"validation","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"ecc2/src/main.rs","lineNumber":3936,"sourceCode":"    files: Vec<String>,\n) -> Result<comms::MessageType> {\n    Ok(match kind {\n        MessageKindArg::Handoff => comms::MessageType::TaskHandoff {\n            task: text,\n            context: context.unwrap_or_default(),\n            priority: priority.into(),\n        },\n        MessageKindArg::Query => comms::MessageType::Query { question: text },\n        MessageKindArg::Response => comms::MessageType::Response { answer: text },\n        MessageKindArg::Completed => comms::MessageType::Completed {\n            summary: text,\n            files_changed: files,\n        },\n        MessageKindArg::Conflict => {\n            let file = files\n                .first()\n                .cloned()\n                .ok_or_else(|| anyhow::anyhow!(\"Conflict messages require at least one --file\"))?;\n            comms::MessageType::Conflict {\n                file,\n                description: context.unwrap_or(text),\n            }\n        }\n    })\n}\n\nfn format_remote_dispatch_action(action: &session::manager::RemoteDispatchAction) -> String {\n    match action {\n        session::manager::RemoteDispatchAction::SpawnedTopLevel => \"spawned top-level\".to_string(),\n        session::manager::RemoteDispatchAction::Assigned(action) => match action {\n            session::manager::AssignmentAction::Spawned => \"spawned delegate\".to_string(),\n            session::manager::AssignmentAction::ReusedIdle => \"reused idle delegate\".to_string(),\n            session::manager::AssignmentAction::ReusedActive => {\n                \"reused active delegate\".to_string()\n            }\n            session::manager::AssignmentAction::DeferredSaturated => {","sourceCodeStart":3918,"sourceCodeEnd":3954,"githubUrl":"https://github.com/affaan-m/ECC/blob/01e15490f04e29cfefe3896951f43db46994d8ee/ecc2/src/main.rs#L3918-L3954","documentation":"Thrown when building a `Conflict` message type: the `files` vector is empty, but a conflict requires at least one file to attribute the conflict to. The code clones `files.first()` and bails via `ok_or_else` if it is `None`. The conflict payload shape (`{ file, description }`) is structurally single-file, so an empty file list cannot be coerced.","triggerScenarios":"Posting a comms message with `--kind conflict` but no `--file` argument. A wrapper that constructs a conflict message and forgets to populate the files list. UI flow that lets users send a conflict without attaching a file.","commonSituations":"Misunderstanding the conflict message contract (assuming `description` alone is enough). Bug in a higher-level dispatcher that drops the files array. Argument parsing edge case where `--file` is consumed but not forwarded.","solutions":["Supply at least one `--file <path>` when using `--kind conflict`.","If you have no file to attribute, pick a more appropriate message kind (e.g. `note` or `query`).","In wrapper code, validate that `files.len() >= 1` before constructing a Conflict variant."],"exampleFix":"// before\necc comms post --kind conflict --text \"merge issue\"\n\n// after\necc comms post --kind conflict --file src/main.rs --text \"merge issue\"","handlingStrategy":"validation","validationCode":"// Validate conflict payload before building the message\nfn build_message(kind: MessageKindArg, text: String, files: Vec<String>, context: Option<String>)\n    -> Result<comms::MessageType>\n{\n    if matches!(kind, MessageKindArg::Conflict) && files.is_empty() {\n        anyhow::bail!(\"Conflict messages require at least one --file\");\n    }\n    // ... rest of construction\n}\n\n// Or at the clap layer: make `--file` required when `--kind conflict`\n//   #[arg(required_if_eq(\"kind\", \"conflict\"))]\n//   files: Vec<String>,","typeGuard":"fn is_valid_conflict(kind: &MessageKindArg, files: &[String]) -> bool {\n    !matches!(kind, MessageKindArg::Conflict) || !files.is_empty()\n}","tryCatchPattern":null,"preventionTips":["Enforce `required_if_eq(\"kind\", \"conflict\")` on the `--file` clap argument so the parser rejects it early.","In wrapper code, assert `files.len() >= 1` for conflict kinds before dispatch.","Document that conflict messages are single-file by design."],"tags":["comms","message","conflict","validation"],"backgroundTag":null,"analyzedSha":"01e15490f04e29cfefe3896951f43db46994d8ee","analyzedAt":"2026-08-13T00:31:08.655Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}