glzr-io/glazewm · error
Cannot run command because subject container is detached.
Error message
Cannot run command because subject container is detached.
What it means
`Wm::run_command` refuses to operate on a container that has been detached from the window-management tree. Detached containers (closed windows, removed workspaces, nodes pending cleanup) have no valid position or siblings, so mutating them is undefined. The command is aborted with this bail to protect tree invariants.
Solutions
- Check `subject_container.is_detached()` before invoking the command and skip or re-resolve the target.
- Re-resolve the target from current state (e.g. focused window) at command execution time instead of caching it.
- If driven by IPC, validate that the window/container ID still exists before sending the command.
- Handle gracefully: treat the bail as a no-op for transient races (window closed concurrently) rather than a fatal error.
- Ensure detach/cleanup paths don't leave stale references in queues or focus history.
Example fix
// before
wm.run_command(state, &command, &subject_container).await?;
// after
if subject_container.is_detached() {
tracing::warn!("Skipping command; subject container detached.");
return Ok(());
}
wm.run_command(state, &command, &subject_container).await?; Defensive patterns
Strategy: validation
Validate before calling
fn command_applicable(c: &Container) -> bool { !c.is_detached() } Type guard
fn as_attached(c: &Container) -> Option<&Container> { if c.is_detached() { None } else { Some(c) } } Try / catch
match wm.run_command(state, &cmd, &subject).await {
Err(e) if e.to_string().contains("detached") => tracing::warn!("Target detached; skipping"),
other => other?,
} Prevention
- Re-resolve the target container from current state at execution time.
- Don't cache ContainerRefs across event-loop ticks or await points.
- Filter out detached containers when queuing commands.
When it happens
Trigger: An `InvokeCommand` arrives whose subject container was detached between selection and execution — e.g. the target window closed after focus moved, a race between an event handler detaching the container and the command processor acting on a stale handle, or a cached `ContainerRef` reused after a relayout.
Common situations: IPC/automation scripts sending commands to a window handle that was just closed; keybindings firing right after the focused window exits; async command queues holding stale container references across event-loop ticks.
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
- Root container does not have a position.
- Invalid tray menu event
- Shell exec failed for
- Failed to send response
- Failed to send event
AI-assisted analysis of glzr-io/glazewm@5709ad0a3c (2026-09-08).
Data as JSON: /api/errors/a94e1830c936a4d3.
Report an issue: GitHub.
Appendix: source
Thrown at packages/wm/src/wm.rs:230
}
Ok(current_subject_container.id())
}
#[allow(clippy::too_many_lines)]
pub fn run_command(
command: &InvokeCommand,
subject_container: Container,
state: &mut WmState,
config: &mut UserConfig,
) -> anyhow::Result<()> {
// No-op if WM is currently paused.
if state.is_paused && *command != InvokeCommand::WmTogglePause {
return Ok(());
}
if subject_container.is_detached() {
bail!("Cannot run command because subject container is detached.");
}
match &command {
InvokeCommand::AdjustBorders(args) => {
match subject_container.as_window_container() {
Ok(window) => {
let args = args.clone();
let border_delta = RectDelta::new(
args.left.unwrap_or(LengthValue::from_px(0)),
args.top.unwrap_or(LengthValue::from_px(0)),
args.right.unwrap_or(LengthValue::from_px(0)),
args.bottom.unwrap_or(LengthValue::from_px(0)),
);
window.set_border_delta(border_delta);
state.pending_sync.queue_container_to_redraw(window);
Ok(())
View on GitHub (pinned to 5709ad0a3c)