Hmbown/CodeWhale · error · io::Error
approval log has no parent
Error message
approval log has no parent
What it means
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.
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
Example fix
// before
let log = ApprovalLog::new(PathBuf::from(""));
// after
let log = ApprovalLog::new(dirs::home_dir().unwrap().join(".codewhale/approvals")); Defensive patterns
Strategy: validation
Validate before calling
let base = dirs::home_dir().ok_or_else(|| io::Error::new(io::ErrorKind::InvalidInput, "no home dir"))?; assert!(base.is_absolute());
Prevention
- 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
When it happens
Trigger: 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.
Common situations: Misconfigured home/data directory producing an empty base path; test code constructing ApprovalLog with a stub base; unusual session_id handling in log_path.
Understand the failure class
Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.
Related errors
- resolving external credential path
- agent profile path is not a directory
- app-server auth token cannot be empty
- Automation admission belongs to a different task store; it…
- Codewhale credentials directory must be owned by the…
AI-assisted analysis of Hmbown/CodeWhale@433685b202 (2026-09-15).
Data as JSON: /api/errors/39dd4cb71fd6f11a.
Report an issue: GitHub.
Appendix: source
Thrown at crates/tui/src/approval_log.rs:275
pub(crate) fn replay(&self, session_id: &str) -> io::Result<ApprovalReplay> {
let receipts = self.load(session_id)?;
ApprovalReplay::from_receipts(&receipts)
.map_err(|err| io::Error::new(io::ErrorKind::InvalidData, err))
}
pub(crate) fn append(&self, session_id: &str, receipt: &ApprovalReceipt) -> io::Result<()> {
let lock_file = self.open_lock_file(session_id)?;
let mut lock = fd_lock::RwLock::new(lock_file);
let _guard = lock.write()?;
let path = self.log_path(session_id)?;
let mut candidate = self.load_unlocked(session_id)?;
candidate.push(receipt.clone());
ApprovalReplay::from_receipts(&candidate)
.map_err(|err| io::Error::new(io::ErrorKind::InvalidData, err))?;
let parent = path.parent().ok_or_else(|| {
io::Error::new(io::ErrorKind::InvalidInput, "approval log has no parent")
})?;
fs::create_dir_all(parent)?;
let mut line = serde_json::to_vec(receipt)
.map_err(|err| io::Error::new(io::ErrorKind::InvalidData, err))?;
line.push(b'\n');
let mut file = OpenOptions::new().create(true).append(true).open(&path)?;
file.write_all(&line)?;
file.sync_all()?;
if let Ok(dir) = File::open(parent) {
let _ = dir.sync_all();
}
Ok(())
}
#[cfg(test)]
pub(crate) fn sessions_dir(&self) -> &std::path::Path {
&self.sessions_dir
}View on GitHub (pinned to 433685b202)