Hmbown/CodeWhale · warning
a window change is already in progress
Error message
a window change is already in progress
What it means
start_toggle serializes window pin/toggle operations with an atomic BUSY flag. If compare_exchange(false, true) fails, another window change is still in flight, so the new request is rejected instead of interleaving with it. This protects HostWindow::capture/dispatch ordering from concurrent toggles.
Solutions
- Retry after a short delay, once the in-flight change completes (BUSY is released by the worker's BusyGuard).
- Debounce/deduplicate toggle keypresses in the UI layer so only one request is in flight.
- If toggles consistently stay busy, investigate a wedged window-pin worker thread (check for a missing permit.send or a hang in toggle_pin).
Defensive patterns
Strategy: retry
Validate before calling
// poll before issuing the toggle
if !window_control_is_idle() {
return; // a change is already in progress
} Try / catch
match start_toggle() {
Err(e) if e.to_string().contains("already in progress") => {
// schedule a retry after the in-flight change completes
schedule_retry(Duration::from_millis(100));
}
Err(e) => report(e),
Ok(()) => {}
} Prevention
- Debounce the toggle hotkey so repeat presses are ignored while busy.
- Serialize toggles through a single UI command channel.
- Treat busy as normal backpressure, not a fault; retry shortly.
When it happens
Trigger: Calling start_toggle twice before the first window-pin worker thread completes (the worker clears BUSY via BusyGuard on exit); rapid repeated keybindings or programmatic toggles issued back-to-back.
Common situations: User mashes the pin hotkey; an automation/test fires toggles faster than the worker applies them; a prior toggle's worker thread is stuck waiting on the completion mailbox.
Understand the failure class
Background: Conflicting config options: "cannot be used together" — configuration validation errors across open-source libraries — this error's family across 162 libraries.
Related errors
- window worker panicked
- A saved trace identifier collided. Try saving again.
- another Codewhale process
- Another pet recorder is using this output.
- Cannot open session : its queued input is already open in…
AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22).
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 73e0f67d83)