glzr-io/glazewm · error
Cannot use an already attached container as replacement…
Error message
Cannot use an already attached container as replacement container.
What it means
`replace_container` swaps an existing child for a replacement, requiring the replacement to be detached. If the replacement container is already attached elsewhere in the tree, it would end up with two parents, so the function bails.
Solutions
- Detach the replacement container before calling `replace_container`
- Verify with `replacement_container.is_detached()` before the call
- Rework the caller so the replacement is created or detached fresh
Example fix
// before replace_container(&replacement, &parent, index)?; // after detach_container(&replacement); replace_container(&replacement, &parent, index)?;
Defensive patterns
Strategy: validation
Validate before calling
if !replacement.is_detached() {
detach_container(&replacement);
}
replace_container(&replacement, &target_parent, index)?; Try / catch
match replace_container(&replacement, &parent, idx) {
Err(e) if e.to_string().contains("already attached") => { /* detach and retry */ }
r => r?,
} Prevention
- Assert `is_detached()` on replacements before swap operations
- Never reuse attached container references as replacements
- Centralize replace logic in one helper that handles detachment
When it happens
Trigger: Passing a container that currently has a parent as `replacement_container` — e.g. replacing a container with another live window's container without detaching it first.
Common situations: Command handlers implementing swap/replace semantics that reuse an attached container reference, or event handlers reusing a container that was never detached.
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
AI-assisted analysis of glzr-io/glazewm@5709ad0a3c (2026-09-08).
Data as JSON: /api/errors/d664a973cb6e6596.
Report an issue: GitHub.
Appendix: source
Thrown at packages/wm/src/commands/container/replace_container.rs:19
use anyhow::{bail, Context};
use wm_common::VecDequeExt;
use super::{attach_container, detach_container, resize_tiling_container};
use crate::{
models::Container,
traits::{CommonGetters, TilingSizeGetters},
};
/// Replaces a container at the specified index.
///
/// The replaced container will be detached from the tree.
pub fn replace_container(
replacement_container: &Container,
target_parent: &Container,
target_index: usize,
) -> anyhow::Result<()> {
if !replacement_container.is_detached() {
bail!(
"Cannot use an already attached container as replacement container."
);
}
let container_to_replace = target_parent
.children()
.get(target_index)
.cloned()
.with_context(|| format!("No container at index {target_index}."))?;
let focus_index = container_to_replace.focus_index();
let tiling_size = container_to_replace
.as_tiling_container()
.map(|c| c.tiling_size());
// TODO: This will cause issues if the detach causes a wrapping split
// container to flatten. Currently, that scenario shouldn't be possible.
// We also can't attach first before detaching, because detaching
View on GitHub (pinned to 5709ad0a3c)