Hmbown/CodeWhale · error · io::Error
approval lock has no parent
Error message
approval lock has no parent
What it means
ApprovalReceiptStore::open_lock_file computes the lock file path by joining sessions_dir with the validated session id and asserts the result has a parent component. It fires only in a degenerate case where the joined path unexpectedly has no parent (e.g. an empty sessions_dir root), since the lock file must live inside a directory.
Solutions
- Ensure sessions_dir passed to ApprovalReceiptStore::new has at least one parent component; a bare filename or empty path cannot host a per-session lock file.
- Use the default_location() constructor, which derives the sessions directory from session_manager::default_sessions_dir().
- Create the sessions directory with its proper absolute path before the first append.
Defensive patterns
Strategy: validation
When it happens
Trigger: Thrown at crates/tui/src/approval_log.rs:200 when the library encounters an invalid state.
Common situations: See trigger scenarios.
AI-assisted analysis of Hmbown/CodeWhale@433685b202 (2026-09-15).
Data as JSON: /api/errors/4d8c748cc066b79a.
Report an issue: GitHub.
Appendix: source
Thrown at crates/tui/src/approval_log.rs:200
));
}
Ok(trimmed)
}
pub(crate) fn log_path(&self, session_id: &str) -> io::Result<PathBuf> {
let session_id = Self::validated_session_id(session_id)?;
Ok(self.sessions_dir.join(session_id).join(APPROVAL_LOG_FILE))
}
fn lock_path(&self, session_id: &str) -> io::Result<PathBuf> {
let session_id = Self::validated_session_id(session_id)?;
Ok(self.sessions_dir.join(session_id).join(APPROVAL_LOCK_FILE))
}
fn open_lock_file(&self, session_id: &str) -> io::Result<File> {
let path = self.lock_path(session_id)?;
let parent = path.parent().ok_or_else(|| {
io::Error::new(io::ErrorKind::InvalidInput, "approval lock has no parent")
})?;
fs::create_dir_all(parent)?;
OpenOptions::new()
.create(true)
.truncate(false)
.read(true)
.write(true)
.open(path)
}
fn open_existing_lock_file(&self, session_id: &str) -> io::Result<Option<File>> {
let path = self.lock_path(session_id)?;
match OpenOptions::new().read(true).open(path) {
Ok(file) => Ok(Some(file)),
Err(err) if err.kind() == io::ErrorKind::NotFound => Ok(None),
Err(err) => Err(err),
}
}View on GitHub (pinned to 433685b202)