{"record":{"id":"62bd4522eea19485","repo":"GitoxideLabs/gitoxide","slug":"removal-target-target-must-be-contained-in-bou","errorCode":null,"errorMessage":"Removal target '{target}' must be contained in boundary '{boundary}'","messagePattern":"Removal target '(.+?)' must be contained in boundary '(.+?)'","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"gix-fs/src/dir/remove.rs","lineNumber":21,"sourceCode":"\n/// A special iterator which communicates its operation through results where…\n///\n/// * `Some(Ok(removed_directory))` is yielded once or more success, followed by `None`\n/// * `Some(Err(std::io::Error))` is yielded exactly once on failure.\npub struct Iter<'a> {\n    cursor: Option<&'a Path>,\n    boundary: &'a Path,\n}\n\n/// Construction\nimpl<'a> Iter<'a> {\n    /// Create a new instance that deletes `target` but will stop at `boundary`, without deleting the latter.\n    /// Returns an error if `boundary` doesn't contain `target`\n    ///\n    /// **Note** that we don't canonicalize the path for performance reasons.\n    pub fn new(target: &'a Path, boundary: &'a Path) -> std::io::Result<Self> {\n        if !target.starts_with(boundary) {\n            return Err(std::io::Error::new(\n                std::io::ErrorKind::InvalidInput,\n                format!(\n                    \"Removal target '{target}' must be contained in boundary '{boundary}'\",\n                    target = target.display(),\n                    boundary = boundary.display()\n                ),\n            ));\n        }\n        let cursor = if target == boundary {\n            None\n        } else if target.exists() {\n            Some(target)\n        } else {\n            None\n        };\n        Ok(Iter { cursor, boundary })\n    }\n}","sourceCodeStart":3,"sourceCodeEnd":39,"githubUrl":"https://github.com/GitoxideLabs/gitoxide/blob/e73179060badf27222d790981fac3f84c1830a7e/gix-fs/src/dir/remove.rs#L3-L39","documentation":"gix-fs' bounded directory remover (`gix_fs::dir::remove::new`) deletes `target` but guarantees it never deletes anything at or above `boundary`. It validates up front that `target`'s path starts with `boundary`; if not, it refuses with `InvalidInput` rather than risk deleting outside the allowed region. Paths are not canonicalized for performance, so the check is lexical.","triggerScenarios":"Calling `DirRemover::new(target, boundary)` where `target` is not a lexical descendant of `boundary` — e.g. non-canonicalized paths like `repo/./objects` vs `repo`, or a target from a different tree.","commonSituations":"Mixing relative and absolute paths; passing symlinked or `..`-containing paths that were never canonicalized; a bug computing the cleanup target during pack/odb garbage collection.","solutions":["Ensure both paths share the same form (both absolute or both relative) and that `target` literally starts with `boundary`.","Canonicalize both paths (`std::fs::canonicalize` or `gix_fs` helpers) before constructing the remover.","Fix the caller logic that computes `target` so it is always inside `boundary`."],"exampleFix":"// before: mixed forms fail the starts_with check\nlet r = gix_fs::dir::remove::DirRemover::new(Path::new(\"repo/objects/pack\"), Path::new(\"/abs/repo\"))?;\n\n// after: canonicalize both first\nlet target = std::fs::canonicalize(\"repo/objects/pack\")?;\nlet boundary = std::fs::canonicalize(\"/abs/repo\")?;\nlet r = gix_fs::dir::remove::DirRemover::new(&target, &boundary)?;","handlingStrategy":"validation","validationCode":"let target = std::fs::canonicalize(target)?;\nlet boundary = std::fs::canonicalize(boundary)?;\nassert!(target.starts_with(&boundary), \"target must be inside boundary\");","typeGuard":null,"tryCatchPattern":"let dir = gix_fs::dir::remove::DirRemover::new(&target, &boundary)\n    .map_err(|e| anyhow::anyhow!(\"bad removal target: {e}\"))?;","preventionTips":["Canonicalize paths before constructing the remover — the containment check is lexical.","Keep target and boundary in the same form (both absolute or both relative).","Assert containment in tests for any code computing cleanup targets."],"tags":["filesystem","path","safety","rust"],"backgroundTag":"invalid-argument-value","analyzedSha":"e73179060badf27222d790981fac3f84c1830a7e","analyzedAt":"2026-09-08T11:26:50.865Z","contentChangedAt":"2026-09-08T11:26:50.865Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}