{"record":{"id":"449e774964865849","repo":"Hmbown/CodeWhale","slug":"artifact-tree-exceeds-export-depth-limit","errorCode":null,"errorMessage":"artifact tree exceeds export depth limit","messagePattern":"artifact tree exceeds export depth limit","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/tui/src/session_export.rs","lineNumber":339,"sourceCode":"        ARTIFACTS_DIR_NAME,\n        0,\n        &mut entries,\n        &mut files,\n    )?;\n    files.sort_by(|left, right| left.0.cmp(&right.0));\n    Ok(files)\n}\n\nfn collect_artifact_files_recursive(\n    sessions_dir: &Path,\n    dir: &Path,\n    prefix: &str,\n    depth: usize,\n    entries: &mut usize,\n    files: &mut Vec<(String, PathBuf)>,\n) -> io::Result<()> {\n    if depth > MAX_ARTIFACT_DEPTH {\n        return Err(io::Error::new(\n            io::ErrorKind::InvalidData,\n            \"artifact tree exceeds export depth limit\",\n        ));\n    }\n    for entry in fs::read_dir(dir)? {\n        let entry = entry?;\n        *entries += 1;\n        if *entries > MAX_ARTIFACT_ENTRIES {\n            return Err(io::Error::new(\n                io::ErrorKind::InvalidData,\n                \"artifact tree exceeds export entry limit\",\n            ));\n        }\n        let file_type = entry.file_type()?;\n        if file_type.is_symlink() {\n            continue;\n        }\n        let child = entry.file_name();","sourceCodeStart":321,"sourceCodeEnd":357,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/tui/src/session_export.rs#L321-L357","documentation":"collect_artifact_files_recursive walks the session's artifacts directory to gather files for a tar export, and refuses to descend deeper than MAX_ARTIFACT_DEPTH. Hitting the limit means the artifact tree is pathologically deep, so the export aborts with InvalidData instead of recursing unboundedly (which would risk stack exhaustion on adversarial trees).","triggerScenarios":"Exporting a session whose artifacts/<subtree> nesting exceeds MAX_ARTIFACT_DEPTH levels, e.g. a tool wrote deeply nested output under the artifacts dir, or an adversarially crafted session directory is exported.","commonSituations":"A build tool or generator created hundreds of nested directories inside artifacts/; a user copied a deep project tree into the artifacts folder; a malicious/corrupted session directory designed to blow up the exporter.","solutions":["Find and flatten the over-deep subtree under the session's artifacts/ directory.","Move genuinely deep content out of artifacts/ (store an archive instead of a deep tree).","Check what wrote the deep tree and cap its nesting depth at the source.","If legitimate content truly needs more depth, raise MAX_ARTIFACT_DEPTH deliberately and document the change."],"exampleFix":"// before\n# artifacts/run-1/a/b/c/d/e/f/g/... (100 levels deep)\n// after\n$ tar -cf deep.tar -C artifacts/run-1 . && rm -rf artifacts/run-1/a\n$ mkdir artifacts/run-1 && mv deep.tar artifacts/run-1/bundle.tar","handlingStrategy":"validation","validationCode":"fn tree_depth_under(dir: &Path, max: usize) -> std::io::Result<bool> {\n    fn walk(d: &Path, depth: usize, max: usize) -> std::io::Result<bool> {\n        if depth > max { return Ok(false); }\n        for e in std::fs::read_dir(d)? {\n            let e = e?;\n            if e.file_type()?.is_dir() && !walk(&e.path(), depth + 1, max)? { return Ok(false); }\n        }\n        Ok(true)\n    }\n    walk(dir, 0, max)\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Cap nesting depth in tools that write under artifacts/.","Bundle deep outputs as a single archive instead of nested directories.","Periodically prune generated artifacts from long-lived sessions."],"tags":["export","filesystem","limits"],"backgroundTag":"file-size-limit-exceeded","analyzedSha":"73e0f67d83c59909b571efdfc88c4bc28c309cb1","analyzedAt":"2026-09-22T01:30:00.501Z","contentChangedAt":"2026-09-22T01:30:00.501Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}