{"record":{"id":"2e5caae6f7119c12","repo":"ruvnet/RuView","slug":"bad-node-id-in-spec","errorCode":null,"errorMessage":"bad node id in {spec:?}","messagePattern":"bad node id in (.+?)","errorType":"validation","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"v2/crates/wifi-densepose-cli/src/room.rs","lineNumber":417,"sourceCode":"            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\n    let mut buf = vec![0u8; RECV_BUF];\n    let mut wins: BTreeMap<u8, VecDeque<f32>> = BTreeMap::new();\n    let start = Instant::now();","sourceCodeStart":399,"sourceCodeEnd":435,"githubUrl":"https://github.com/ruvnet/RuView/blob/4685618388a5e49fad5b3005806f3bdd6a7c25c3/v2/crates/wifi-densepose-cli/src/room.rs#L399-L435","documentation":"After splitting the `--node-bank` value on the first colon, the id part is parsed as `u8`. Anything that is not an integer in 0..=255 — out-of-range values like `300`, letters, or a Windows drive letter (`C:\\banks\\n1.json` makes `C` the id) — fails the parse and raises this error before the bank is read.","triggerScenarios":"`--node-bank 256:bank.json`; `--node-bank node1:bank.json`; on Windows an absolute path `--node-bank C:\\banks\\n1.json` where `split_once(':')` consumes the drive-letter colon; whitespace or a sign in the id.","commonSituations":"Node ids planned above 255 in firmware; Windows paths; copy-paste of ids like `01 ` with trailing space from a spreadsheet.","solutions":["Use a node id in 0..=255 that matches the firmware-configured id: `--node-bank 3:./banks/node3.json`.","On Windows, pass a relative path so the first colon is the `N:` separator, not the drive letter.","Trim whitespace and drop leading `+`/zeros beyond one digit from ids in scripts."],"exampleFix":"# before (Windows drive colon swallowed as separator)\nroom-watch --node-bank C:\\banks\\n1.json\n# after\nroom-watch --node-bank 1:banks\\n1.json","handlingStrategy":"validation","validationCode":"fn node_id_in_range(spec: &str) -> bool {\n    spec.split_once(':')\n        .map(|(id, _)| id.parse::<u8>().is_ok())\n        .unwrap_or(false)\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":["Remember split_once(':') splits at the FIRST colon — never put a drive-letter absolute path after the id on Windows.","Keep the node-id map (0..=255) documented next to the physical ESP32 nodes.","Strip whitespace/signs from ids sourced from spreadsheets or env vars."],"tags":["rust","cli","parsing","multistatic","windows"],"backgroundTag":null,"analyzedSha":"4685618388a5e49fad5b3005806f3bdd6a7c25c3","analyzedAt":"2026-08-16T06:09:40.886Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}