{"record":{"id":"95b8c97d0b0782dc","repo":"ruvnet/RuView","slug":"node-bank-must-be-n-path-got-spec","errorCode":null,"errorMessage":"--node-bank must be N:path (got {spec:?})","messagePattern":"--node-bank must be N:path \\(got (.+?)\\)","errorType":"validation","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"v2/crates/wifi-densepose-cli/src/room.rs","lineNumber":414,"sourceCode":"            println!(\n                \"presence={pres:<7} posture={post:<8} breathing={br:<8} heart={hr:<7} restless={rest}{flags}\"\n            );\n            last_print = Instant::now();\n        }\n    }\n    Ok(())\n}\n\n/// Multistatic `room-watch`: fuse several co-located nodes (ADR-029/151).\nasync fn room_watch_multi(args: RoomWatchArgs) -> Result<()> {\n    use std::collections::{BTreeMap, VecDeque};\n\n    let mut mix = MultiNodeMixture::new();\n    let mut node_ids: Vec<u8> = Vec::new();\n    for spec in &args.node_bank {\n        let (id_s, path) = spec\n            .split_once(':')\n            .ok_or_else(|| anyhow::anyhow!(\"--node-bank must be N:path (got {spec:?})\"))?;\n        let id: u8 = id_s\n            .parse()\n            .map_err(|_| anyhow::anyhow!(\"bad node id in {spec:?}\"))?;\n        let raw = std::fs::read_to_string(path)\n            .map_err(|e| anyhow::anyhow!(\"cannot read {path}: {e}\"))?;\n        let bank = SpecialistBank::from_json(&raw).map_err(|e| anyhow::anyhow!(\"{e}\"))?;\n        let baseline = bank.baseline_id.clone();\n        mix.add_node(id, bank, baseline);\n        node_ids.push(id);\n    }\n    eprintln!(\"[room-watch] multistatic over nodes {node_ids:?}\");\n\n    let addr = format!(\"{}:{}\", args.bind, args.udp_port);\n    let socket = UdpSocket::bind(&addr)\n        .await\n        .map_err(|e| anyhow::anyhow!(\"cannot bind {addr}: {e}\"))?;\n    eprintln!(\"[room-watch] fusing on udp://{addr} (window={} frames)\", args.window);\n","sourceCodeStart":396,"sourceCodeEnd":432,"githubUrl":"https://github.com/ruvnet/RuView/blob/4685618388a5e49fad5b3005806f3bdd6a7c25c3/v2/crates/wifi-densepose-cli/src/room.rs#L396-L432","documentation":"In multistatic `room-watch` (entered as soon as any `--node-bank` value is supplied), each value must encode a node as `N:path`. The code does `spec.split_once(':')`; if the value contains no colon at all, split returns `None` and this error aborts startup before any socket is opened. It is a pure CLI usage error, not an environmental one.","triggerScenarios":"Passing `--node-bank ./room-bank.json` (missing the `N:` prefix); passing a comma list `--node-bank 1:a.json,2:b.json` instead of repeating the flag; an empty value from an unset shell variable.","commonSituations":"Users migrating from the single-node `--bank` flag who drop the prefix; docs whose line-wrapping splits the value; quoting mistakes in launch scripts.","solutions":["Give each node as `N:PATH`, repeating the flag per node: `--node-bank 1:./banks/node1.json --node-bank 2:./banks/node2.json`.","Ensure exactly one `N:PATH` per flag occurrence — no comma-separated lists.","Check wrapper scripts for empty or misquoted variables."],"exampleFix":"# before\nroom-watch --node-bank ./node1.json\n# after\nroom-watch --node-bank 1:./node1.json --node-bank 2:./node2.json","handlingStrategy":"validation","validationCode":"fn valid_node_bank_spec(spec: &str) -> bool {\n    match spec.split_once(':') {\n        Some((id, path)) => id.parse::<u8>().is_ok() && !path.is_empty(),\n        None => false,\n    }\n}","typeGuard":"fn parse_node_bank_spec(spec: &str) -> Option<(u8, &str)> {\n    let (id, path) = spec.split_once(':')?;\n    let id = id.parse::<u8>().ok()?;\n    (!path.is_empty()).then(|| (id, path))\n}","tryCatchPattern":null,"preventionTips":["Validate every --node-bank value against ^\\d{1,3}:.+ before launching the CLI from scripts.","Repeat the flag per node; the option does not accept comma lists.","Fail fast in wrappers when a spec has no ':' rather than letting the daemon abort later."],"tags":["rust","cli","argument-parsing","multistatic","usage"],"backgroundTag":null,"analyzedSha":"4685618388a5e49fad5b3005806f3bdd6a7c25c3","analyzedAt":"2026-08-16T06:09:40.886Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}