{"record":{"id":"d5fe63abc74e5caa","repo":"affaan-m/ECC","slug":"label-must-use-key-value-form-value","errorCode":null,"errorMessage":"{label} must use key=value form: {value}","messagePattern":"(.+?) must use key=value form: (.+?)","errorType":"validation","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"ecc2/src/main.rs","lineNumber":8593,"sourceCode":"        to_id,\n        &comms::MessageType::TaskHandoff {\n            task: from_session.task,\n            context,\n            priority: comms::TaskPriority::Normal,\n        },\n    )\n}\n\nfn parse_template_vars(values: &[String]) -> Result<BTreeMap<String, String>> {\n    parse_key_value_pairs(values, \"template vars\")\n}\n\nfn parse_key_value_pairs(values: &[String], label: &str) -> Result<BTreeMap<String, String>> {\n    let mut vars = BTreeMap::new();\n    for value in values {\n        let (key, raw_value) = value\n            .split_once('=')\n            .ok_or_else(|| anyhow::anyhow!(\"{label} must use key=value form: {value}\"))?;\n        let key = key.trim();\n        let raw_value = raw_value.trim();\n        if key.is_empty() || raw_value.is_empty() {\n            anyhow::bail!(\"{label} must use non-empty key=value form: {value}\");\n        }\n        vars.insert(key.to_string(), raw_value.to_string());\n    }\n    Ok(vars)\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use crate::config::Config;\n    use crate::session::store::StateStore;\n    use crate::session::{Session, SessionMetrics, SessionState};\n    use chrono::{Duration, Utc};\n    use std::fs;","sourceCodeStart":8575,"sourceCodeEnd":8611,"githubUrl":"https://github.com/affaan-m/ECC/blob/01e15490f04e29cfefe3896951f43db46994d8ee/ecc2/src/main.rs#L8575-L8611","documentation":"Thrown by parse_key_value_pairs (used for template vars, graph metadata, observation details) when one of the provided string entries has no '=' delimiter at all. The parser requires every entry to be in key=value form; an entry lacking '=' cannot be split into a key and value and is rejected.","triggerScenarios":"Passing a CLI flag like --var component (no '=') or --metadata lang (no '='), or a positional value that omits the delimiter. The label in the message identifies which flag (e.g. 'template vars', 'graph metadata', 'graph observation details').","commonSituations":"User forgets the '=value' part; shell quoting strips the '='; a script builds args by joining key and value with a space instead of '='; copy-pasting from docs that show the key only.","solutions":["Rewrite the offending entry as key=value, e.g. '--var component=billing' instead of '--var component'.","If scripting, construct args with format!(\"{key}={value}\") rather than space-separated tokens.","Quote each entry so the shell does not split on '=' or whitespace.","Re-read the error: it includes the exact value that failed, so fix that one entry."],"exampleFix":"# before\necc2 run --var component --var area=oauth\n\n# after\necc2 run --var component=billing --var area=oauth","handlingStrategy":"validation","validationCode":"fn is_key_value(entry: &str) -> bool {\n    entry.split_once('=').is_some()\n}\n\n// validate CLI args up front\nfor v in &vars {\n    if !is_key_value(v) {\n        return Err(anyhow!(\"{v} must be key=value\"));\n    }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always pass '--flag key=value'.","When scripting, build entries with format!(\"{k}={v}\").","Quote each entry to protect '=' from the shell."],"tags":["cli","input-validation","parsing","key-value"],"backgroundTag":null,"analyzedSha":"01e15490f04e29cfefe3896951f43db46994d8ee","analyzedAt":"2026-08-13T00:31:08.655Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}