{"record":{"id":"39dd4cb71fd6f11a","repo":"Hmbown/CodeWhale","slug":"approval-log-has-no-parent","errorCode":null,"errorMessage":"approval log has no parent","messagePattern":"approval log has no parent","errorType":"exception","errorClass":"io::Error","httpStatus":null,"severity":"error","filePath":"crates/tui/src/approval_log.rs","lineNumber":275,"sourceCode":"\n    pub(crate) fn replay(&self, session_id: &str) -> io::Result<ApprovalReplay> {\n        let receipts = self.load(session_id)?;\n        ApprovalReplay::from_receipts(&receipts)\n            .map_err(|err| io::Error::new(io::ErrorKind::InvalidData, err))\n    }\n\n    pub(crate) fn append(&self, session_id: &str, receipt: &ApprovalReceipt) -> io::Result<()> {\n        let lock_file = self.open_lock_file(session_id)?;\n        let mut lock = fd_lock::RwLock::new(lock_file);\n        let _guard = lock.write()?;\n        let path = self.log_path(session_id)?;\n        let mut candidate = self.load_unlocked(session_id)?;\n        candidate.push(receipt.clone());\n        ApprovalReplay::from_receipts(&candidate)\n            .map_err(|err| io::Error::new(io::ErrorKind::InvalidData, err))?;\n\n        let parent = path.parent().ok_or_else(|| {\n            io::Error::new(io::ErrorKind::InvalidInput, \"approval log has no parent\")\n        })?;\n        fs::create_dir_all(parent)?;\n        let mut line = serde_json::to_vec(receipt)\n            .map_err(|err| io::Error::new(io::ErrorKind::InvalidData, err))?;\n        line.push(b'\\n');\n        let mut file = OpenOptions::new().create(true).append(true).open(&path)?;\n        file.write_all(&line)?;\n        file.sync_all()?;\n        if let Ok(dir) = File::open(parent) {\n            let _ = dir.sync_all();\n        }\n        Ok(())\n    }\n\n    #[cfg(test)]\n    pub(crate) fn sessions_dir(&self) -> &std::path::Path {\n        &self.sessions_dir\n    }","sourceCodeStart":257,"sourceCodeEnd":293,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/433685b2024e7bc4c99e1e2e326bcad39b4d9d65/crates/tui/src/approval_log.rs#L257-L293","documentation":"append() resolves the log path and requires a parent directory component before creating it with create_dir_all. Path::parent() returns None only for paths with no directory component (e.g. a bare filename root), so this InvalidInput error indicates the configured base directory for approval logs resolved to something unusable.","triggerScenarios":"log_path(session_id) yields a path whose parent() is None — essentially only when the base directory configuration collapsed to a relative bare filename or an empty/odd root.","commonSituations":"Misconfigured home/data directory producing an empty base path; test code constructing ApprovalLog with a stub base; unusual session_id handling in log_path.","solutions":["Check how ApprovalLog's base directory is constructed (home dir / config) and ensure it is an absolute directory path","Pass an explicit valid base directory when constructing ApprovalLog instead of relying on resolution","Inspect log_path() for the given session_id and fix any sanitization that could empty the directory component","Add a startup check that the configured log directory is absolute and non-empty"],"exampleFix":"// before\nlet log = ApprovalLog::new(PathBuf::from(\"\"));\n\n// after\nlet log = ApprovalLog::new(dirs::home_dir().unwrap().join(\".codewhale/approvals\"));","handlingStrategy":"validation","validationCode":"let base = dirs::home_dir().ok_or_else(|| io::Error::new(io::ErrorKind::InvalidInput, \"no home dir\"))?;\nassert!(base.is_absolute());","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Configure the approval-log base directory explicitly at startup","Assert the base directory is absolute and non-empty before constructing ApprovalLog","Set HOME in service/container environments"],"tags":["rust","filesystem","configuration","paths"],"backgroundTag":"invalid-config-value","analyzedSha":"433685b2024e7bc4c99e1e2e326bcad39b4d9d65","analyzedAt":"2026-09-15T12:24:24.634Z","contentChangedAt":"2026-09-15T12:24:24.634Z","schemaVersion":2},"datasetVersion":"2026-09-22T06:17:15.046Z"}