{"record":{"id":"34d9f3850d89b980","repo":"ruvnet/RuView","slug":"data-dir-not-accessible-e","errorCode":null,"errorMessage":"data_dir not accessible {}: {e}","messagePattern":"data_dir not accessible (.+?): (.+?)","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"v2/crates/wifi-densepose-pointcloud/src/training.rs","lineNumber":53,"sourceCode":"/// through user-supplied names.\nfn safe_join(base: &Path, child: &str) -> Result<PathBuf> {\n    // Reject absolute children and any `..` components up front.\n    let child_path = Path::new(child);\n    if child_path.is_absolute() {\n        return Err(anyhow!(\"child path must be relative: {child}\"));\n    }\n    for comp in child_path.components() {\n        if matches!(comp, std::path::Component::ParentDir) {\n            return Err(anyhow!(\"child path may not contain `..`: {child}\"));\n        }\n    }\n\n    let joined = base.join(child_path);\n    // Canonicalise base (must exist) and verify joined starts with it. If the\n    // joined file doesn't exist yet we canonicalise the parent.\n    let canonical_base = base\n        .canonicalize()\n        .map_err(|e| anyhow!(\"data_dir not accessible {}: {e}\", base.display()))?;\n    let canonical_parent = joined\n        .parent()\n        .ok_or_else(|| anyhow!(\"no parent for {}\", joined.display()))?;\n    let canonical_parent = canonical_parent\n        .canonicalize()\n        .map_err(|e| anyhow!(\"parent not accessible {}: {e}\", canonical_parent.display()))?;\n    if !canonical_parent.starts_with(&canonical_base) {\n        return Err(anyhow!(\n            \"refusing to write outside data_dir: {}\",\n            joined.display()\n        ));\n    }\n    Ok(canonical_parent.join(\n        joined\n            .file_name()\n            .ok_or_else(|| anyhow!(\"no filename for {}\", joined.display()))?,\n    ))\n}","sourceCodeStart":35,"sourceCodeEnd":71,"githubUrl":"https://github.com/ruvnet/RuView/blob/4685618388a5e49fad5b3005806f3bdd6a7c25c3/v2/crates/wifi-densepose-pointcloud/src/training.rs#L35-L71","documentation":"`safe_join`, used by every filesystem write in the training module, canonicalizes the session's `data_dir` root to verify containment. If `base.canonicalize()` fails — the directory no longer exists, a component lacks search (execute) permission, or a symlink loop exists — the write is aborted with this error carrying the OS cause.","triggerScenarios":"The data dir was deleted after `TrainingSession::new` succeeded; a network mount (NFS/SMB) dropped between session creation and a write; permission revocation on an ancestor directory; symlink cycles inside the path.","commonSituations":"`rm -rf` of the output dir mid-session (common in test harnesses); unmounted USB/NFS roots; running the writer under a different uid than the creator; container volume remounts.","solutions":["Recreate the directory and rebuild the session: `mkdir -p <data_dir>` then a fresh `TrainingSession::new(...)`.","Verify the dir is searchable by the same user running the session: `sudo -u <user> ls <data_dir>`.","For removable/network roots, confirm the mount is present before issuing writes."],"exampleFix":"// before\nsession.save()?; // data_dir deleted underneath -> \"data_dir not accessible\"\n// after\nif !std::path::Path::new(&dir).is_dir() {\n    std::fs::create_dir_all(&dir)?;\n}\nlet session = TrainingSession::new(&dir)?;\nsession.save()?;","handlingStrategy":"validation","validationCode":"// Before any write API on a long-lived session.\nfn data_dir_alive(dir: &std::path::Path) -> bool {\n    dir.is_dir() && dir.canonicalize().is_ok()\n}","typeGuard":null,"tryCatchPattern":"match session.append(frame) {\n    Err(e) if e.downcast_ref::<std::io::Error>()\n        .map(|io| io.kind() == std::io::ErrorKind::NotFound)\n        .unwrap_or(false) =>\n    {\n        // data_dir vanished: recreate and rebuild the session, then retry once\n        std::fs::create_dir_all(dir)?;\n        let session = TrainingSession::new(&dir)?;\n        session.append(frame)\n    }\n    r => r,\n}","preventionTips":["Keep the data_dir's lifetime tied to the session's; never `rm -rf` it mid-capture.","Prefer local filesystems over network mounts for data_dir during training.","Run the writer under the uid that owns the dir."],"tags":["rust","filesystem","io","canonicalization","training"],"backgroundTag":null,"analyzedSha":"4685618388a5e49fad5b3005806f3bdd6a7c25c3","analyzedAt":"2026-08-16T06:09:40.886Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}