{"record":{"id":"a680110b4a65d260","repo":"Hmbown/CodeWhale","slug":"cannot-open-session-its-queued-input-is-already-open-in","errorCode":null,"errorMessage":"Cannot open session {}: its queued input is already open in another window, or its previous writes are still finishing ({})","messagePattern":"Cannot open session (.+?): its queued input is already open in another window, or its previous writes are still finishing \\((.+?)\\)","errorType":"exception","errorClass":"io::Error","httpStatus":null,"severity":"error","filePath":"crates/tui/src/session_manager.rs","lineNumber":2248,"sourceCode":"    /// resume. A per-write lock is insufficient: the second editor's stale\n    /// snapshot would overwrite the first as soon as its write completed.\n    pub fn acquire_offline_queue_lease(\n        &self,\n        session_id: &str,\n    ) -> io::Result<std::sync::Arc<OfflineQueueLease>> {\n        let session_id = self.validated_session_id(session_id)?.to_string();\n        let directory = self.checkpoints_dir();\n        fs::create_dir_all(&directory)?;\n        let path = directory.join(format!(\"{session_id}.offline_queue.lock\"));\n        let file = fs::OpenOptions::new()\n            .create(true)\n            .truncate(false)\n            .read(true)\n            .write(true)\n            .open(path)?;\n        let mut lock = fd_lock::RwLock::new(file);\n        let guard = lock.try_write().map_err(|error| {\n            io::Error::new(\n                error.kind(),\n                format!(\"Cannot open session {session_id}: its queued input is already open in another window, or its previous writes are still finishing ({error})\"),\n            )\n        })?;\n        // fd-lock's guard borrows its owner. Retain the underlying descriptor\n        // instead so this lease can travel with asynchronous writes. Forgetting\n        // this non-owning guard keeps the OS lock held; the final Arc explicitly\n        // unlocks in Drop. The OS also releases it when the process crashes.\n        std::mem::forget(guard);\n        Ok(std::sync::Arc::new(OfflineQueueLease {\n            session_id,\n            _file: lock.into_inner(),\n        }))\n    }\n\n    /// Park this session's offline queue (queued + draft messages).\n    ///\n    /// Queues are keyed per session (`checkpoints/<session_id>.offline_queue.json`)","sourceCodeStart":2230,"sourceCodeEnd":2266,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/tui/src/session_manager.rs#L2230-L2266","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"for attempt in 0..3 {\n    match manager.open_session(&session_id) {\n        Err(e) if e.to_string().contains(\"already open in another window\") && attempt < 2 => {\n            std::thread::sleep(Duration::from_millis(500));\n        }\n        Err(e) if e.to_string().contains(\"already open in another window\") => {\n            eprintln!(\"session {session_id} is locked elsewhere; close it and retry\");\n            return;\n        }\n        other => { other?; break; }\n    }\n}","preventionTips":["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"],"tags":["file-lock","concurrency","session"],"backgroundTag":"file-lock-contention","analyzedSha":"73e0f67d83c59909b571efdfc88c4bc28c309cb1","analyzedAt":"2026-09-22T01:30:00.501Z","contentChangedAt":"2026-09-22T01:30:00.501Z","schemaVersion":2},"datasetVersion":"2026-09-22T21:17:16.096Z"}