diff --git a/src/Build.UnitTests/ProjectCache/ProjectCacheTests.cs b/src/Build.UnitTests/ProjectCache/ProjectCacheTests.cs
index 74e5a5bf932..047918b5c92 100644
--- a/src/Build.UnitTests/ProjectCache/ProjectCacheTests.cs
+++ b/src/Build.UnitTests/ProjectCache/ProjectCacheTests.cs
@@ -1342,6 +1342,41 @@ public void EngineShouldHandleExceptionsFromCachePluginViaGraphBuild(ErrorLocati
}
}
+ [Fact]
+ public async Task CriticalExceptionFromGraphBuildCompletesSubmission()
+ {
+ const string exceptionMessage = "Critical exception from graph build";
+
+ var project = _env.CreateFile(
+ "1.proj",
+ """
+
+
+
+ """);
+ var graph = new ProjectGraph(project.Path);
+ var cache = new DelegatingMockCache(
+ (_, _, _) => throw new InternalErrorException(exceptionMessage));
+ var buildParameters = new BuildParameters
+ {
+ ProjectCacheDescriptor = ProjectCacheDescriptor.FromInstance(cache),
+ ShutdownInProcNodeOnBuildFinish = true
+ };
+ var requestData = new GraphBuildRequestData(graph, ["Build"]);
+
+ Task buildTask = Task.Run(
+ () =>
+ {
+ using var buildManager = new BuildManager();
+ return Should.Throw(() => buildManager.Build(buildParameters, requestData));
+ });
+
+ Task completedTask = await Task.WhenAny(buildTask, Task.Delay(TimeSpan.FromSeconds(10)));
+
+ completedTask.ShouldBeSameAs(buildTask, "Graph builds should complete after a critical exception.");
+ (await buildTask).Message.ShouldContain(exceptionMessage);
+ }
+
[Fact]
public void EndBuildShouldGetCalledOnceWhenItThrowsExceptionsFromGraphBuilds()
{
diff --git a/src/Build/BackEnd/BuildManager/BuildManager.cs b/src/Build/BackEnd/BuildManager/BuildManager.cs
index 4b69ec5a6e2..7753a5fafd2 100644
--- a/src/Build/BackEnd/BuildManager/BuildManager.cs
+++ b/src/Build/BackEnd/BuildManager/BuildManager.cs
@@ -1772,9 +1772,9 @@ private void ExecuteSubmission(GraphBuildSubmission submission)
{
ExecuteGraphBuildScheduler(submission);
}
- catch (Exception ex) when (!ExceptionHandling.IsCriticalException(ex))
+ catch (Exception ex)
{
- HandleSubmissionException(submission, ex);
+ HandleGraphSubmissionException(submission, ex);
}
},
_executionCancellationTokenSource!.Token,
@@ -1783,13 +1783,25 @@ private void ExecuteSubmission(GraphBuildSubmission submission)
}
}
// The handling of submission exception needs to be done outside of the lock
- catch (Exception ex) when (!ExceptionHandling.IsCriticalException(ex))
+ catch (Exception ex)
{
- HandleSubmissionException(submission, ex);
+ HandleGraphSubmissionException(submission, ex);
throw;
}
}
+ private void HandleGraphSubmissionException(GraphBuildSubmission submission, Exception ex)
+ {
+ if (ExceptionHandling.IsCriticalException(ex))
+ {
+ OnThreadException(ex);
+ }
+ else
+ {
+ HandleSubmissionException(submission, ex);
+ }
+ }
+
///
/// Creates the traversal and metaproject instances necessary to represent the solution and populates new configurations with them.
///