Hmbown/CodeWhale · error · io::Error
Cannot open session : its queued input is already open in…
Error message
Cannot open session {}: its queued input is already open in another window, or its previous writes are still finishing ({}) What it means
Opening a session requires an exclusive write lease (fd_lock::RwLock::try_write) on its queued-input file. When another window already holds the lease, or a previous write has not finished releasing it, try_write fails and the manager rewraps the error with a message naming the session id and the underlying cause.
Solutions
- Close the other window/process that has this session open, then retry opening it
- Wait briefly and retry — a finishing write releases the lock on its own
- If a stale process is dead but the lock persists, kill the leftover Codewhale process (check boot-owner records / ps) and reopen
- As a last resort, remove the orphaned lock by ensuring no process holds the file descriptor, then reopen the session
Defensive patterns
Strategy: retry
Try / catch
for attempt in 0..3 {
match manager.open_session(&session_id) {
Err(e) if e.to_string().contains("already open in another window") && attempt < 2 => {
std::thread::sleep(Duration::from_millis(500));
}
Err(e) if e.to_string().contains("already open in another window") => {
eprintln!("session {session_id} is locked elsewhere; close it and retry");
return;
}
other => { other?; break; }
}
} Prevention
- Open each session in exactly one window
- Ensure previous Codewhale processes have exited before reopening a session
- After a crash, kill leftover processes before resuming the session
When it happens
Trigger: Calling the session-open/lease path while the same session's input file is write-locked by a second process/window, or immediately after a crashed/pending write that has not yet released the fd lock.
Common situations: The same session opened in two terminal windows; a previous Codewhale process still shutting down or hung while holding the lease; an async writer from the last run that never released the guard.
Related errors
- Cannot open session : its queued input is already open in…
- Owner lock was replaced
- Session Runtime ownership changed; reopen the session…
- A saved trace identifier collided. Try saving again.
- a window change is already in progress
AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22).
Data as JSON: /api/errors/a680110b4a65d260.
Report an issue: GitHub.
Appendix: source
Thrown at crates/tui/src/session_manager.rs:2248
/// resume. A per-write lock is insufficient: the second editor's stale
/// snapshot would overwrite the first as soon as its write completed.
pub fn acquire_offline_queue_lease(
&self,
session_id: &str,
) -> io::Result<std::sync::Arc<OfflineQueueLease>> {
let session_id = self.validated_session_id(session_id)?.to_string();
let directory = self.checkpoints_dir();
fs::create_dir_all(&directory)?;
let path = directory.join(format!("{session_id}.offline_queue.lock"));
let file = fs::OpenOptions::new()
.create(true)
.truncate(false)
.read(true)
.write(true)
.open(path)?;
let mut lock = fd_lock::RwLock::new(file);
let guard = lock.try_write().map_err(|error| {
io::Error::new(
error.kind(),
format!("Cannot open session {session_id}: its queued input is already open in another window, or its previous writes are still finishing ({error})"),
)
})?;
// fd-lock's guard borrows its owner. Retain the underlying descriptor
// instead so this lease can travel with asynchronous writes. Forgetting
// this non-owning guard keeps the OS lock held; the final Arc explicitly
// unlocks in Drop. The OS also releases it when the process crashes.
std::mem::forget(guard);
Ok(std::sync::Arc::new(OfflineQueueLease {
session_id,
_file: lock.into_inner(),
}))
}
/// Park this session's offline queue (queued + draft messages).
///
/// Queues are keyed per session (`checkpoints/<session_id>.offline_queue.json`)View on GitHub (pinned to 73e0f67d83)