{"record":{"id":"7ede84fbe4fe7e11","repo":"ruvnet/RuView","slug":"cannot-canonicalise-data-dir-e","errorCode":null,"errorMessage":"cannot canonicalise data_dir {}: {e}","messagePattern":"cannot canonicalise data_dir (.+?): (.+?)","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"v2/crates/wifi-densepose-pointcloud/src/training.rs","lineNumber":171,"sourceCode":"            rmse: f32::MAX,\n        }\n    }\n}\n\nimpl TrainingSession {\n    /// Create a new training session rooted at `data_dir`.\n    ///\n    /// `data_dir` must not contain `..` components — we reject path traversal\n    /// attempts from CLI/API input. The directory is created if missing and\n    /// then canonicalised so every subsequent write stays inside it.\n    pub fn new(data_dir: &str) -> Result<Self> {\n        let path = sanitize_data_path(data_dir)?;\n        std::fs::create_dir_all(&path)\n            .map_err(|e| anyhow!(\"failed to create data_dir {}: {e}\", path.display()))?;\n        // Canonicalise so path-traversal checks in safe_join have a fixed root.\n        let path = path\n            .canonicalize()\n            .map_err(|e| anyhow!(\"cannot canonicalise data_dir {}: {e}\", path.display()))?;\n\n        // Load existing calibration if available\n        let cal_path = safe_join(&path, \"calibration.json\")\n            // safe_join needs the parent to exist; for initial load that's always data_dir\n            .or_else(|_| Ok::<_, anyhow::Error>(path.join(\"calibration.json\")))?;\n        let calibration = if cal_path.exists() {\n            let data = std::fs::read_to_string(&cal_path)?;\n            serde_json::from_str(&data).unwrap_or_default()\n        } else {\n            DepthCalibration::default()\n        };\n\n        Ok(Self {\n            samples: Vec::new(),\n            calibration,\n            data_dir: path,\n        })\n    }","sourceCodeStart":153,"sourceCodeEnd":189,"githubUrl":"https://github.com/ruvnet/RuView/blob/4685618388a5e49fad5b3005806f3bdd6a7c25c3/v2/crates/wifi-densepose-pointcloud/src/training.rs#L153-L189","documentation":"Immediately after creating it, `TrainingSession::new` canonicalizes the data dir so `safe_join` has a fixed containment root. Failure here means the directory could not be resolved after creation: it vanished between `create_dir_all` and `canonicalize`, a parent denies traversal, or the path traverses a symlink loop / flaky FUSE-automount. It is rare and usually indicates a race or an exotic filesystem rather than a config mistake.","triggerScenarios":"A concurrent cleaner (`rm -rf` in a test harness) deleting the fresh dir; cyclic symlinks in the path; transient FUSE/automount errors; NFS stale file handles immediately after creation.","commonSituations":"Test suites that wipe output dirs while sessions start; overlayfs quirks inside containers; NAS-backed data roots with aggressive automount timeouts.","solutions":["Retry session creation once the interfering cleanup stops (typically succeeds on the second attempt).","Pass a stable, symlink-free absolute path for the data dir.","Keep the data dir on a local, always-mounted filesystem during capture/training runs."],"exampleFix":"// before\nlet s = TrainingSession::new(&dir)?; // cleaner deletes dir between mkdir and canonicalize\n// after\nlet s = TrainingSession::new(&dir)\n    .or_else(|_| TrainingSession::new(&dir))?; // retry once after the race window","handlingStrategy":"retry","validationCode":"fn data_dir_resolvable(dir: &std::path::Path) -> bool {\n    dir.is_dir() && dir.canonicalize().is_ok()\n}","typeGuard":null,"tryCatchPattern":"let session = match TrainingSession::new(&dir) {\n    Ok(s) => s,\n    Err(e) if e.to_string().contains(\"cannot canonicalise data_dir\") => {\n        // transient race or flaky mount: recreate once, then retry\n        std::fs::create_dir_all(&dir)?;\n        TrainingSession::new(&dir)?\n    }\n    Err(e) => return Err(e),\n};","preventionTips":["Don't run cleanup jobs that wipe the output dir concurrently with session creation.","Pass symlink-free absolute paths for data_dir.","Keep data_dir off automounted FUSE/NFS roots during capture runs."],"tags":["rust","filesystem","race-condition","canonicalization","training"],"backgroundTag":null,"analyzedSha":"4685618388a5e49fad5b3005806f3bdd6a7c25c3","analyzedAt":"2026-08-16T06:09:40.886Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}