Hmbown/CodeWhale · warning · anyhow::Error
a window change is already in progress
Error message
a window change is already in progress
What it means
Thrown by start_toggle when the window-control BUSY atomic flag is already true, meaning another window toggle (pin) operation is currently in flight. The module serializes window changes: only one toggle may run at a time, enforced by a compare_exchange on BUSY, so a second concurrent request is rejected instead of racing the worker thread.
Solutions
- Wait for the in-progress window change to complete and retry
- Debounce the UI action so repeated clicks are ignored while busy
- If BUSY appears stuck, investigate the window-pin worker thread for a stall in permit.send
Defensive patterns
Strategy: retry
Try / catch
match start_toggle(...) {
Err(e) if e.to_string().contains("already in progress") => {
std::thread::sleep(Duration::from_millis(150));
start_toggle(...)?; // single retry after in-flight change completes
}
other => other?,
} Prevention
- Debounce window-pin UI clicks
- Track an is-busy flag in your own automation
- Investigate worker stalls if busy never clears
When it happens
Trigger: Clicking a pin/toggle control twice quickly before the first worker finishes; programmatically invoking start_toggle concurrently from two threads; a previous toggle whose BusyGuard was never dropped due to a stall in permit delivery.
Common situations: Impatient double-click on the window-pin control; automation scripts issuing rapid toggles; a hung window worker keeping BUSY set.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- A saved trace identifier collided. Try saving again.
- Another pet owner is running
- Another pet recorder is using this output.
- Cannot open session : its queued input is already open in…
- catalog cache unavailable
AI-assisted analysis of Hmbown/CodeWhale@433685b202 (2026-09-15).
Data as JSON: /api/errors/03db4d41d244b3c0.
Report an issue: GitHub.
Appendix: source
Thrown at crates/tui/src/tui/window_control.rs:190
}
if Instant::now() >= deadline {
return Ok(false);
}
std::thread::sleep(Duration::from_millis(15));
}
}
pub(super) fn start_toggle(
completion_tx: Option<tokio::sync::mpsc::Sender<crate::tui::app::DispatchApplyFn>>,
) -> Result<()> {
// Reserve delivery before changing the window. A headless test App has
// no mailbox and cannot accidentally manipulate its real terminal.
let permit = completion_tx
.context("window completion mailbox is unavailable")?
.try_reserve_owned()
.context("window completion mailbox is full or closed")?;
BUSY.compare_exchange(false, true, Ordering::AcqRel, Ordering::Acquire)
.map_err(|_| anyhow::anyhow!("a window change is already in progress"))?;
let busy = BusyGuard;
// Foreground selection belongs to the user's action, before dispatch;
// the worker must not pick a different window after focus changes.
let host = HostWindow::capture()?;
std::thread::Builder::new()
.name("window-pin".into())
.spawn(move || {
let result = std::panic::catch_unwind(|| toggle_pin(host))
.unwrap_or_else(|_| Err(anyhow::anyhow!("window worker panicked")));
let apply: crate::tui::app::DispatchApplyFn = Box::new(move |app, _, _| {
super::show_result(app, result);
Ok(())
});
permit.send(apply);
drop(busy);
})?;
Ok(())
}View on GitHub (pinned to 433685b202)