{"record":{"id":"4519a46f413e3066","repo":"ruvnet/RuView","slug":"cannot-read-path-e","errorCode":null,"errorMessage":"cannot read {path}: {e}","messagePattern":"cannot read (.+?): (.+?)","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"v2/crates/wifi-densepose-cli/src/room.rs","lineNumber":419,"sourceCode":"    }\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();\n    let mut last_print = Instant::now();\n","sourceCodeStart":401,"sourceCodeEnd":437,"githubUrl":"https://github.com/ruvnet/RuView/blob/4685618388a5e49fad5b3005806f3bdd6a7c25c3/v2/crates/wifi-densepose-cli/src/room.rs#L401-L437","documentation":"In the multistatic loop, each bank path extracted from `N:path` is read with `std::fs::read_to_string`, and any OS error is surfaced verbatim: ENOENT (missing file), EACCES (no read permission), EISDIR (a directory was passed), or 'stream did not contain valid UTF-8' for binary content. The file must be the plain-text JSON `SpecialistBank` serialization produced by the training/enroll tooling.","triggerScenarios":"Running the CLI from a different working directory than the bank's relative path; passing a directory as the path; a gzipped or otherwise binary bank file; unreadable ownership after an scp as root.","commonSituations":"Relative paths breaking when launched by systemd or a script whose CWD is `/`; files transferred with wrong ownership; trailing newline/whitespace injected into the path by shell variables.","solutions":["Pass an absolute path: `--node-bank 1:/home/op/banks/node1.json`.","Verify the file is readable plain JSON: `test -r <path> && head -c1 <path>` should print `{`.","Fix permissions (`chmod +r`) or ownership if the error text says `Permission denied`."],"exampleFix":"# before (launched by systemd, CWD=/)\nroom-watch --node-bank 1:node1.json\n# after\nroom-watch --node-bank 1:/opt/ruview/banks/node1.json","handlingStrategy":"validation","validationCode":"fn bank_loadable(path: &str) -> bool {\n    let p = std::path::Path::new(path);\n    p.is_file()\n        && std::fs::metadata(p).map(|m| !m.permissions().readonly()).unwrap_or(false)\n        && std::fs::read_to_string(p).map(|s| s.trim_start().starts_with('{')).unwrap_or(false)\n}","typeGuard":null,"tryCatchPattern":"Err(e) => {\n    if let Some(io) = e.downcast_ref::<std::io::Error>() {\n        match io.kind() {\n            std::io::ErrorKind::NotFound => eprintln!(\"bank file missing: check path/CWD\"),\n            std::io::ErrorKind::PermissionDenied => eprintln!(\"bank unreadable: chmod +r\"),\n            _ => eprintln!(\"bank read failed: {io}\"),\n        }\n    }\n}","preventionTips":["Use absolute bank paths when launching from service managers whose CWD differs.","Regenerate banks with the same CLI version that consumes them.","Validate the first byte is '{' in deploy scripts to catch binary/truncated transfers."],"tags":["rust","filesystem","cli","multistatic","io"],"backgroundTag":null,"analyzedSha":"4685618388a5e49fad5b3005806f3bdd6a7c25c3","analyzedAt":"2026-08-16T06:09:40.886Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}