{"record":{"id":"56c2fca2c2cbdd35","repo":"Hmbown/CodeWhale","slug":"artifact-tree-exceeds-export-entry-limit","errorCode":null,"errorMessage":"artifact tree exceeds export entry limit","messagePattern":"artifact tree exceeds export entry limit","errorType":"validation","errorClass":"io::Error (InvalidData)","httpStatus":null,"severity":"error","filePath":"crates/tui/src/session_export.rs","lineNumber":348,"sourceCode":"fn 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();\n        let child = child\n            .to_str()\n            .filter(|name| !name.contains(['\\\\', ':']))\n            .ok_or_else(|| {\n                io::Error::new(\n                    io::ErrorKind::InvalidData,\n                    \"artifact name is not portable UTF-8\",\n                )\n            })?;","sourceCodeStart":330,"sourceCodeEnd":366,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/433685b2024e7bc4c99e1e2e326bcad39b4d9d65/crates/tui/src/session_export.rs#L330-L366","documentation":"The artifact walk counts every directory entry it visits and enforces MAX_ARTIFACT_ENTRIES across the whole tree. Exceeding the cap aborts the export with InvalidData, protecting the exporter from huge artifact trees that would blow up archive size, memory, and time.","triggerScenarios":"Exporting a session whose artifacts directory (recursively) contains more entries than MAX_ARTIFACT_ENTRIES — e.g. thousands of log files, cache fragments, or an extracted node_modules tree left in the artifacts folder.","commonSituations":"Long-running sessions that accumulate per-step logs; tools that drop per-frame or per-test artifacts; accidentally pointing the artifacts dir at a broad cache directory.","solutions":["Prune or clean the artifacts directory, keeping only meaningful files.","Aggregate many small files into one archive/bundle before placing them in artifacts.","Raise MAX_ARTIFACT_ENTRIES if the volume is legitimate, accepting a larger export.","Count entries first (`find <dir> | wc -l`) to see what is bloating the tree."],"exampleFix":"// before\n// artifacts/logs/ contains 100,000 frame dumps -> export fails\n// after: keep only the summary\nfor f in glob(\"<artifacts>/logs/frame-*.png\") { fs::remove_file(f)?; }\nwrite_session_archive(&session, dir, &out, options)?;","handlingStrategy":"validation","validationCode":"fn count_entries(dir: &Path) -> usize {\n    fn walk(d: &Path, n: &mut usize) {\n        if let Ok(rd) = std::fs::read_dir(d) {\n            for e in rd.flatten() { *n += 1; if e.file_type().map(|t| t.is_dir()).unwrap_or(false) { walk(&e.path(), n); } }\n        }\n    }\n    let mut n = 0; walk(dir, &mut n); n\n}\n// if count_entries(artifacts) > MAX_ARTIFACT_ENTRIES { prune first }","typeGuard":null,"tryCatchPattern":"match write_session_archive(&session, dir, out, opts) {\n    Err(e) if e.to_string().contains(\"entry limit\") => {\n        eprintln!(\"too many artifact files; clean the artifacts directory\");\n    }\n    other => other?,\n}","preventionTips":["Aggregate per-step logs into single files instead of thousands of small ones","Exclude cache directories from artifacts","Monitor artifacts size/entry count during long sessions"],"tags":["filesystem","limits","session-export"],"backgroundTag":"file-size-limit-exceeded","analyzedSha":"433685b2024e7bc4c99e1e2e326bcad39b4d9d65","analyzedAt":"2026-09-15T12:24:24.634Z","contentChangedAt":"2026-09-15T12:24:24.634Z","schemaVersion":2},"datasetVersion":"2026-09-22T01:17:13.364Z"}