Hmbown/CodeWhale · error
Another pet owner is running
Error message
Another pet owner is running
What it means
serve() takes an exclusive advisory file lock (fd_lock::RwLock::try_write) on owner.lock inside the shared habitat root. If another pet_watch owner process already holds it, try_write fails and this error is returned instead of starting a second owner.
Solutions
- Find and terminate the running pet owner process before starting another one
- Wait for the existing owner to release the lock (exit or finish)
- Verify no orphaned owner survives (ps / container list) and clean it up; the lock is held via a live fd, so removing the file alone will not help
Defensive patterns
Strategy: retry
Validate before calling
// Check whether another owner holds the lock before calling serve()
let probe = std::fs::OpenOptions::new().write(true).open(root.join("owner.lock"));
let can_take = probe.map(|f| fd_lock::RwLock::new(f).try_write().is_ok()); Try / catch
match owner::serve(&root) {
Err(e) if e.to_string().contains("Another pet owner is running") => {
eprintln!("Owner already running; attaching to it instead.");
}
r => r?,
} Prevention
- Single-instance-check (pid file or lock probe) before launching serve
- Shut down the previous TUI instance cleanly so the lock fd is released
- In containers, ensure the previous owner process exits on restart
When it happens
Trigger: Calling serve() when another pet owner process is alive and holds owner.lock — e.g. a previous instance still running, a crashed instance whose lock file persists while its process still lives, or launching a second owner from another terminal.
Common situations: Starting the TUI twice in the same workspace; a stale hung owner from a prior session; container restart where the old owner never exited.
Understand the failure class
Background: "already exists" / EEXIST / FileAlreadyExistsException: what the 'file already exists' error means and how to fix it — this error's family across 37 libraries.
Related errors
- Cannot open session : its queued input is already open in…
- Cannot open session : its queued input is already open in…
- config lock path contains invalid Unicode and cannot be…
- Owner lock was replaced
- Refusing a non-regular settings lock at
AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22).
Data as JSON: /api/errors/05958e757782b3c4.
Report an issue: GitHub.
Appendix: source
Thrown at crates/tui/src/tui/pet_watch/owner.rs:301
// startup line and stop reason are the operator's only output.
#[allow(clippy::print_stdout, clippy::print_stderr)]
pub fn serve(root: PathBuf, requested_port: u16) -> anyhow::Result<()> {
std::fs::create_dir_all(&root)?;
#[cfg(unix)]
{
use std::os::unix::fs::{MetadataExt, PermissionsExt};
let metadata = std::fs::symlink_metadata(&root)?;
if !metadata.is_dir() || metadata.uid() != unsafe { libc::geteuid() } {
anyhow::bail!("Pet directory must belong to this user and cannot be a link");
}
std::fs::set_permissions(&root, std::fs::Permissions::from_mode(0o700))?;
}
let lock_path = WorkspaceFile::open(&root, Path::new("owner.lock"), true)?;
let original = lock_path.open_update(true, false)?;
let mut lifetime = fd_lock::RwLock::new(original.try_clone()?);
let _guard = lifetime
.try_write()
.map_err(|_| anyhow::anyhow!("Another pet owner is running"))?;
let mut store = Store::at(&root)?;
let previous = store.load()?;
let mut saved = if let Some(text) = previous {
let value: Saved = serde_json::from_str(&text)?;
if value.version != 1
|| uuid::Uuid::parse_str(&value.identity).is_err()
|| value.token.len() != 64
|| !value.token.bytes().all(|b| b.is_ascii_hexdigit())
|| !valid_source(&value.source)
|| value.clients.len() > MAX_CLIENTS
|| !value.appearance.valid()
{
anyhow::bail!("Invalid shared habitat; the existing file was kept");
}
value
} else {
Saved {
version: 1,View on GitHub (pinned to 73e0f67d83)