Skip to content

Commit 38411db

Browse files
HavenDVclaude
andcommitted
Fix FileScanner crash on Parallel.ForEach AggregateException
Wrap both the parallel and sequential subdirectory loops with try/catch for IOException, UnauthorizedAccessException, and PathTooLongException. Also catch AggregateException from Parallel.ForEach to prevent crashes when scanning directories with problematic paths (symlink loops, network mounts timing out, paths exceeding OS limits). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 5dd9806 commit 38411db

1 file changed

Lines changed: 32 additions & 7 deletions

File tree

src/cli/Tiktoken.Cli/IO/FileScanner.cs

Lines changed: 32 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -331,13 +331,31 @@ private void ScanDirectory(
331331
if (depth <= 1 && subDirs.Count > 1)
332332
{
333333
var bags = new ConcurrentBag<(List<string> Results, ScanStats Stats)>();
334-
Parallel.ForEach(subDirs, subDir =>
334+
try
335335
{
336-
var localResults = new List<string>();
337-
var localSubStats = new ScanStats();
338-
ScanDirectory(subDir, rootPath, rootPrefixLen, effectiveIgnores, effectiveHasFileRules, localResults, localSubStats, depth + 1);
339-
bags.Add((localResults, localSubStats));
340-
});
336+
Parallel.ForEach(subDirs, subDir =>
337+
{
338+
var localResults = new List<string>();
339+
var localSubStats = new ScanStats();
340+
try
341+
{
342+
ScanDirectory(subDir, rootPath, rootPrefixLen, effectiveIgnores, effectiveHasFileRules, localResults, localSubStats, depth + 1);
343+
}
344+
catch (Exception ex) when (ex is IOException or UnauthorizedAccessException or PathTooLongException)
345+
{
346+
localSubStats.DirsErrored++;
347+
}
348+
bags.Add((localResults, localSubStats));
349+
});
350+
}
351+
catch (AggregateException ae)
352+
{
353+
// If any worker threw an unhandled exception, count it and continue
354+
foreach (var _ in ae.InnerExceptions)
355+
{
356+
localStats.DirsErrored++;
357+
}
358+
}
341359

342360
foreach (var (subResults, subStats) in bags)
343361
{
@@ -349,7 +367,14 @@ private void ScanDirectory(
349367
{
350368
foreach (var subDir in subDirs)
351369
{
352-
ScanDirectory(subDir, rootPath, rootPrefixLen, effectiveIgnores, effectiveHasFileRules, results, localStats, depth + 1);
370+
try
371+
{
372+
ScanDirectory(subDir, rootPath, rootPrefixLen, effectiveIgnores, effectiveHasFileRules, results, localStats, depth + 1);
373+
}
374+
catch (Exception ex) when (ex is IOException or UnauthorizedAccessException or PathTooLongException)
375+
{
376+
localStats.DirsErrored++;
377+
}
353378
}
354379
}
355380
}

0 commit comments

Comments
 (0)