{"record":{"id":"d664a973cb6e6596","repo":"glzr-io/glazewm","slug":"cannot-use-an-already-attached-container-as-replac","errorCode":null,"errorMessage":"Cannot use an already attached container as replacement container.","messagePattern":"Cannot use an already attached container as replacement container\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/wm/src/commands/container/replace_container.rs","lineNumber":19,"sourceCode":"use anyhow::{bail, Context};\r\nuse wm_common::VecDequeExt;\r\n\r\nuse super::{attach_container, detach_container, resize_tiling_container};\r\nuse crate::{\r\n  models::Container,\r\n  traits::{CommonGetters, TilingSizeGetters},\r\n};\r\n\r\n/// Replaces a container at the specified index.\r\n///\r\n/// The replaced container will be detached from the tree.\r\npub fn replace_container(\r\n  replacement_container: &Container,\r\n  target_parent: &Container,\r\n  target_index: usize,\r\n) -> anyhow::Result<()> {\r\n  if !replacement_container.is_detached() {\r\n    bail!(\r\n      \"Cannot use an already attached container as replacement container.\"\r\n    );\r\n  }\r\n\r\n  let container_to_replace = target_parent\r\n    .children()\r\n    .get(target_index)\r\n    .cloned()\r\n    .with_context(|| format!(\"No container at index {target_index}.\"))?;\r\n\r\n  let focus_index = container_to_replace.focus_index();\r\n  let tiling_size = container_to_replace\r\n    .as_tiling_container()\r\n    .map(|c| c.tiling_size());\r\n\r\n  // TODO: This will cause issues if the detach causes a wrapping split\r\n  // container to flatten. Currently, that scenario shouldn't be possible.\r\n  // We also can't attach first before detaching, because detaching\r","sourceCodeStart":1,"sourceCodeEnd":37,"githubUrl":"https://github.com/glzr-io/glazewm/blob/5709ad0a3c7c386bbc3e38166a865ffc12937515/packages/wm/src/commands/container/replace_container.rs#L1-L37","documentation":"`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.","triggerScenarios":"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.","commonSituations":"Command handlers implementing swap/replace semantics that reuse an attached container reference, or event handlers reusing a container that was never detached.","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"],"exampleFix":"// before\nreplace_container(&replacement, &parent, index)?;\n// after\ndetach_container(&replacement);\nreplace_container(&replacement, &parent, index)?;","handlingStrategy":"validation","validationCode":"if !replacement.is_detached() {\n  detach_container(&replacement);\n}\nreplace_container(&replacement, &target_parent, index)?;","typeGuard":null,"tryCatchPattern":"match replace_container(&replacement, &parent, idx) {\n  Err(e) if e.to_string().contains(\"already attached\") => { /* detach and retry */ }\n  r => r?,\n}","preventionTips":["Assert `is_detached()` on replacements before swap operations","Never reuse attached container references as replacements","Centralize replace logic in one helper that handles detachment"],"tags":["state","container-tree","invariant"],"backgroundTag":"invalid-state-transition","analyzedSha":"5709ad0a3c7c386bbc3e38166a865ffc12937515","analyzedAt":"2026-09-08T03:26:40.288Z","contentChangedAt":"2026-09-08T03:26:40.288Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}