{"record":{"id":"4d8c748cc066b79a","repo":"Hmbown/CodeWhale","slug":"approval-lock-has-no-parent","errorCode":null,"errorMessage":"approval lock has no parent","messagePattern":"approval lock has no parent","errorType":"exception","errorClass":"io::Error","httpStatus":null,"severity":"error","filePath":"crates/tui/src/approval_log.rs","lineNumber":200,"sourceCode":"            ));\n        }\n        Ok(trimmed)\n    }\n\n    pub(crate) fn log_path(&self, session_id: &str) -> io::Result<PathBuf> {\n        let session_id = Self::validated_session_id(session_id)?;\n        Ok(self.sessions_dir.join(session_id).join(APPROVAL_LOG_FILE))\n    }\n\n    fn lock_path(&self, session_id: &str) -> io::Result<PathBuf> {\n        let session_id = Self::validated_session_id(session_id)?;\n        Ok(self.sessions_dir.join(session_id).join(APPROVAL_LOCK_FILE))\n    }\n\n    fn open_lock_file(&self, session_id: &str) -> io::Result<File> {\n        let path = self.lock_path(session_id)?;\n        let parent = path.parent().ok_or_else(|| {\n            io::Error::new(io::ErrorKind::InvalidInput, \"approval lock has no parent\")\n        })?;\n        fs::create_dir_all(parent)?;\n        OpenOptions::new()\n            .create(true)\n            .truncate(false)\n            .read(true)\n            .write(true)\n            .open(path)\n    }\n\n    fn open_existing_lock_file(&self, session_id: &str) -> io::Result<Option<File>> {\n        let path = self.lock_path(session_id)?;\n        match OpenOptions::new().read(true).open(path) {\n            Ok(file) => Ok(Some(file)),\n            Err(err) if err.kind() == io::ErrorKind::NotFound => Ok(None),\n            Err(err) => Err(err),\n        }\n    }","sourceCodeStart":182,"sourceCodeEnd":218,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/433685b2024e7bc4c99e1e2e326bcad39b4d9d65/crates/tui/src/approval_log.rs#L182-L218","documentation":"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.","triggerScenarios":"Thrown at crates/tui/src/approval_log.rs:200 when the library encounters an invalid state.","commonSituations":"See trigger scenarios.","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."],"exampleFix":null,"handlingStrategy":"validation","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":[],"tags":[],"backgroundTag":null,"analyzedSha":"433685b2024e7bc4c99e1e2e326bcad39b4d9d65","analyzedAt":"2026-09-15T12:24:24.634Z","contentChangedAt":"2026-09-15T12:24:24.634Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}