ruvnet/RuView · error · anyhow::Error
--node-bank must be N:path (got {spec:?})
Error message
--node-bank must be N:path (got {spec:?}) What it means
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.
Source
Thrown at v2/crates/wifi-densepose-cli/src/room.rs:414
println!(
"presence={pres:<7} posture={post:<8} breathing={br:<8} heart={hr:<7} restless={rest}{flags}"
);
last_print = Instant::now();
}
}
Ok(())
}
/// Multistatic `room-watch`: fuse several co-located nodes (ADR-029/151).
async fn room_watch_multi(args: RoomWatchArgs) -> Result<()> {
use std::collections::{BTreeMap, VecDeque};
let mut mix = MultiNodeMixture::new();
let mut node_ids: Vec<u8> = Vec::new();
for spec in &args.node_bank {
let (id_s, path) = spec
.split_once(':')
.ok_or_else(|| anyhow::anyhow!("--node-bank must be N:path (got {spec:?})"))?;
let id: u8 = id_s
.parse()
.map_err(|_| anyhow::anyhow!("bad node id in {spec:?}"))?;
let raw = std::fs::read_to_string(path)
.map_err(|e| anyhow::anyhow!("cannot read {path}: {e}"))?;
let bank = SpecialistBank::from_json(&raw).map_err(|e| anyhow::anyhow!("{e}"))?;
let baseline = bank.baseline_id.clone();
mix.add_node(id, bank, baseline);
node_ids.push(id);
}
eprintln!("[room-watch] multistatic over nodes {node_ids:?}");
let addr = format!("{}:{}", args.bind, args.udp_port);
let socket = UdpSocket::bind(&addr)
.await
.map_err(|e| anyhow::anyhow!("cannot bind {addr}: {e}"))?;
eprintln!("[room-watch] fusing on udp://{addr} (window={} frames)", args.window);
View on GitHub (pinned to 4685618388)
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.
Example fix
# before room-watch --node-bank ./node1.json # after room-watch --node-bank 1:./node1.json --node-bank 2:./node2.json
Defensive patterns
Strategy: validation
Validate before calling
fn valid_node_bank_spec(spec: &str) -> bool {
match spec.split_once(':') {
Some((id, path)) => id.parse::<u8>().is_ok() && !path.is_empty(),
None => false,
}
} Type guard
fn parse_node_bank_spec(spec: &str) -> Option<(u8, &str)> {
let (id, path) = spec.split_once(':')?;
let id = id.parse::<u8>().ok()?;
(!path.is_empty()).then(|| (id, path))
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: Users migrating from the single-node `--bank` flag who drop the prefix; docs whose line-wrapping splits the value; quoting mistakes in launch scripts.
Related errors
- bad node id in {spec:?}
- cannot read {path}: {e}
- --hap-device-id is required when HAP is enabled
- --hap-advertise-addr is required when HAP is enabled
- --hap-setup-code is required when creating a HAP pairing sto
AI-assisted analysis of ruvnet/RuView@4685618388 (2026-08-16).
Data as JSON: /api/errors/95b8c97d0b0782dc.
Report an issue: GitHub.