From 745331fd3a4884ba7718fa6988d8fff92169ade8 Mon Sep 17 00:00:00 2001 From: Jan Provaznik Date: Tue, 24 Mar 2026 13:26:23 +0100 Subject: [PATCH 1/7] Fix TraceEngine file contention deadlock in multithreaded mode In multithreaded (-mt) mode, multiple in-proc node engines run in the same process. Each engine's TraceEngine() method wrote to the same EngineTrace_{PID}.txt file with FileShare.Read. When two engines traced concurrently, the second got an IOException, which propagated through QueueAction's error handler and fatally crashed the ActionBlock work queue. All subsequent Post() calls were silently rejected, causing request completions to be dropped and the scheduler to deadlock. Fix: - Use per-node trace files: EngineTrace_{PID}_{NodeId}.txt - Catch IOException in TraceEngine so trace failures can never crash the build engine Added regression test that enables MSBUILDDEBUGSCHEDULER=1 during a multithreaded build with parallel child projects. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../BackEnd/BuildManager_Tests.cs | 64 +++++++++++++++++++ .../BuildRequestEngine/BuildRequestEngine.cs | 24 +++++-- 2 files changed, 83 insertions(+), 5 deletions(-) diff --git a/src/Build.UnitTests/BackEnd/BuildManager_Tests.cs b/src/Build.UnitTests/BackEnd/BuildManager_Tests.cs index b77c905d344..6d5aaeed2bc 100644 --- a/src/Build.UnitTests/BackEnd/BuildManager_Tests.cs +++ b/src/Build.UnitTests/BackEnd/BuildManager_Tests.cs @@ -4622,5 +4622,69 @@ public void MultiThreadedBuild_SharedConfiguration_DoesNotCrash() _logger.AssertLogContains($"Child{i} built"); } } + + /// + /// Regression test: when MSBUILDDEBUGSCHEDULER is enabled in multithreaded (-mt) mode, + /// multiple in-proc node engines write trace output to files. Previously, all engines + /// wrote to the same EngineTrace_{PID}.txt file with FileShare.Read, causing IOException + /// when two engines traced concurrently. The IOException fatally crashed the ActionBlock + /// work queue, silently dropping subsequent request completions and causing a deadlock. + /// + /// The fix uses per-node trace files (EngineTrace_{PID}_{NodeId}.txt) and catches IO + /// exceptions in TraceEngine() so they can never crash the build engine. + /// + [Fact] + public void MultiThreadedBuild_WithDebugSchedulerTracing_DoesNotDeadlock() + { + string debugPath = _env.CreateFolder().Path; + _env.SetEnvironmentVariable("MSBUILDDEBUGSCHEDULER", "1"); + _env.SetEnvironmentVariable("MSBUILDDEBUGPATH", debugPath); + + // Create a root project that builds two independent child projects in parallel. + // This forces multiple in-proc nodes to run concurrently, which triggers + // concurrent TraceEngine() calls. + string child1 = _env.CreateFile(".proj").Path; + string child2 = _env.CreateFile(".proj").Path; + string root = _env.CreateFile(".proj").Path; + + string childContent = CleanupFileContents(""" + + + + + + """); + File.WriteAllText(child1, childContent); + File.WriteAllText(child2, childContent); + + string rootContent = CleanupFileContents($""" + + + + + + + """); + File.WriteAllText(root, rootContent); + + var buildParameters = new BuildParameters + { + MaxNodeCount = 4, + EnableNodeReuse = false, + MultiThreaded = true, + DisableInProcNode = false, + SaveOperatingEnvironment = false, + Loggers = [_logger], + }; + + var data = new BuildRequestData(root, new Dictionary(), null, + ["Build"], null); + + BuildManager.DefaultBuildManager.Dispose(); + BuildResult result = BuildManager.DefaultBuildManager.Build(buildParameters, data); + + result.OverallResult.ShouldBe(BuildResultCode.Success); + _logger.AssertLogContains("Root completed"); + } } } diff --git a/src/Build/BackEnd/Components/BuildRequestEngine/BuildRequestEngine.cs b/src/Build/BackEnd/Components/BuildRequestEngine/BuildRequestEngine.cs index 42d90d11290..8a024f39848 100644 --- a/src/Build/BackEnd/Components/BuildRequestEngine/BuildRequestEngine.cs +++ b/src/Build/BackEnd/Components/BuildRequestEngine/BuildRequestEngine.cs @@ -1561,13 +1561,27 @@ private void TraceEngine(string format, params object[] stuff) { lock (this) { - FileUtilities.EnsureDirectoryExists(_debugDumpPath); + try + { + FileUtilities.EnsureDirectoryExists(_debugDumpPath); + + // Use per-node trace files to avoid file contention when multiple in-proc + // nodes run in the same process (multithreaded / -mt mode). + int nodeId = _componentHost?.BuildParameters?.NodeId ?? 0; + string traceFile = string.Format(CultureInfo.CurrentCulture, Path.Combine(_debugDumpPath, @"EngineTrace_{0}_{1}.txt"), EnvironmentUtilities.CurrentProcessId, nodeId); - using (StreamWriter file = FileUtilities.OpenWrite(string.Format(CultureInfo.CurrentCulture, Path.Combine(_debugDumpPath, @"EngineTrace_{0}.txt"), EnvironmentUtilities.CurrentProcessId), append: true)) + using (StreamWriter file = FileUtilities.OpenWrite(traceFile, append: true)) + { + string message = String.Format(CultureInfo.CurrentCulture, format, stuff); + file.WriteLine("{0}({1})-{2}: {3}", Thread.CurrentThread.Name, Environment.CurrentManagedThreadId, DateTime.UtcNow.Ticks, message); + file.Flush(); + } + } + catch (IOException) { - string message = String.Format(CultureInfo.CurrentCulture, format, stuff); - file.WriteLine("{0}({1})-{2}: {3}", Thread.CurrentThread.Name, Environment.CurrentManagedThreadId, DateTime.UtcNow.Ticks, message); - file.Flush(); + // Trace file IO failures must never crash the build engine. + // In multithreaded mode, file contention can occur if multiple engines + // happen to share a trace file path despite the per-node naming. } } } From ff27105670d0870c2cb95ecb4943e106bfde5e2a Mon Sep 17 00:00:00 2001 From: Jan Provaznik Date: Mon, 30 Mar 2026 18:50:31 +0200 Subject: [PATCH 2/7] Fix TraceEngine file contention deadlock in multithreaded mode In -mt mode, multiple in-proc BuildRequestEngine instances share one process. Each engine's TraceEngine() used lock(this), which only serialized within that instance. Concurrent FileStream opens to EngineTrace_{PID}.txt with FileShare.Read caused IOException, which fatally crashed the ActionBlock work queue and caused a scheduler deadlock. Fix: - Replace lock(this) with a static lock (s_traceLock) so all engines in the same process serialize trace writes to a single file. - Catch non-critical exceptions in TraceEngine, matching the defensive pattern already used by Scheduler.TraceScheduler. - Add regression test with Timeout=30s to fail fast on deadlock. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../BackEnd/BuildManager_Tests.cs | 42 +++++++++++-------- .../BuildRequestEngine/BuildRequestEngine.cs | 22 +++++----- 2 files changed, 35 insertions(+), 29 deletions(-) diff --git a/src/Build.UnitTests/BackEnd/BuildManager_Tests.cs b/src/Build.UnitTests/BackEnd/BuildManager_Tests.cs index 6d5aaeed2bc..17a0ae93607 100644 --- a/src/Build.UnitTests/BackEnd/BuildManager_Tests.cs +++ b/src/Build.UnitTests/BackEnd/BuildManager_Tests.cs @@ -4625,27 +4625,27 @@ public void MultiThreadedBuild_SharedConfiguration_DoesNotCrash() /// /// Regression test: when MSBUILDDEBUGSCHEDULER is enabled in multithreaded (-mt) mode, - /// multiple in-proc node engines write trace output to files. Previously, all engines - /// wrote to the same EngineTrace_{PID}.txt file with FileShare.Read, causing IOException - /// when two engines traced concurrently. The IOException fatally crashed the ActionBlock - /// work queue, silently dropping subsequent request completions and causing a deadlock. + /// multiple in-proc node engines write trace output to the same EngineTrace_{PID}.txt file. + /// Previously, each engine used lock(this) which only serialized within one instance, + /// allowing concurrent FileStream opens with FileShare.Read. The IOException fatally crashed + /// the ActionBlock work queue, silently dropping subsequent request completions and causing + /// a deadlock. /// - /// The fix uses per-node trace files (EngineTrace_{PID}_{NodeId}.txt) and catches IO - /// exceptions in TraceEngine() so they can never crash the build engine. + /// The fix uses a static lock across all engine instances so a single trace file is safe, + /// and catches non-critical exceptions so trace failures can never crash the build engine. /// - [Fact] - public void MultiThreadedBuild_WithDebugSchedulerTracing_DoesNotDeadlock() + [Fact(Timeout = 30_000)] + public async System.Threading.Tasks.Task MultiThreadedBuild_WithDebugSchedulerTracing_DoesNotDeadlock() { string debugPath = _env.CreateFolder().Path; _env.SetEnvironmentVariable("MSBUILDDEBUGSCHEDULER", "1"); _env.SetEnvironmentVariable("MSBUILDDEBUGPATH", debugPath); - // Create a root project that builds two independent child projects in parallel. + // Create a root project that builds several independent child projects in parallel. // This forces multiple in-proc nodes to run concurrently, which triggers // concurrent TraceEngine() calls. - string child1 = _env.CreateFile(".proj").Path; - string child2 = _env.CreateFile(".proj").Path; - string root = _env.CreateFile(".proj").Path; + const int childCount = 4; + string[] childPaths = new string[childCount]; string childContent = CleanupFileContents(""" @@ -4654,22 +4654,28 @@ public void MultiThreadedBuild_WithDebugSchedulerTracing_DoesNotDeadlock() """); - File.WriteAllText(child1, childContent); - File.WriteAllText(child2, childContent); + + for (int i = 0; i < childCount; i++) + { + childPaths[i] = _env.CreateFile(".proj").Path; + File.WriteAllText(childPaths[i], childContent); + } string rootContent = CleanupFileContents($""" - + """); - File.WriteAllText(root, rootContent); + + string rootPath = _env.CreateFile(".proj").Path; + File.WriteAllText(rootPath, rootContent); var buildParameters = new BuildParameters { - MaxNodeCount = 4, + MaxNodeCount = childCount + 1, EnableNodeReuse = false, MultiThreaded = true, DisableInProcNode = false, @@ -4677,7 +4683,7 @@ public void MultiThreadedBuild_WithDebugSchedulerTracing_DoesNotDeadlock() Loggers = [_logger], }; - var data = new BuildRequestData(root, new Dictionary(), null, + var data = new BuildRequestData(rootPath, new Dictionary(), null, ["Build"], null); BuildManager.DefaultBuildManager.Dispose(); diff --git a/src/Build/BackEnd/Components/BuildRequestEngine/BuildRequestEngine.cs b/src/Build/BackEnd/Components/BuildRequestEngine/BuildRequestEngine.cs index 8a024f39848..f26a7581064 100644 --- a/src/Build/BackEnd/Components/BuildRequestEngine/BuildRequestEngine.cs +++ b/src/Build/BackEnd/Components/BuildRequestEngine/BuildRequestEngine.cs @@ -36,6 +36,12 @@ namespace Microsoft.Build.BackEnd /// internal class BuildRequestEngine : IBuildRequestEngine, IBuildComponent { + /// + /// Static lock serializing trace file writes across all BuildRequestEngine instances. + /// In multithreaded (-mt) mode, multiple engines share the same process and trace file. + /// + private static readonly object s_traceLock = new(); + /// /// The starting unresolved configuration id assigned by the engine. /// @@ -1559,29 +1565,23 @@ private void TraceEngine(string format, params object[] stuff) { if (_debugDumpState) { - lock (this) + lock (s_traceLock) { try { FileUtilities.EnsureDirectoryExists(_debugDumpPath); - // Use per-node trace files to avoid file contention when multiple in-proc - // nodes run in the same process (multithreaded / -mt mode). - int nodeId = _componentHost?.BuildParameters?.NodeId ?? 0; - string traceFile = string.Format(CultureInfo.CurrentCulture, Path.Combine(_debugDumpPath, @"EngineTrace_{0}_{1}.txt"), EnvironmentUtilities.CurrentProcessId, nodeId); - - using (StreamWriter file = FileUtilities.OpenWrite(traceFile, append: true)) + using (StreamWriter file = FileUtilities.OpenWrite(string.Format(CultureInfo.CurrentCulture, Path.Combine(_debugDumpPath, @"EngineTrace_{0}.txt"), EnvironmentUtilities.CurrentProcessId), append: true)) { string message = String.Format(CultureInfo.CurrentCulture, format, stuff); file.WriteLine("{0}({1})-{2}: {3}", Thread.CurrentThread.Name, Environment.CurrentManagedThreadId, DateTime.UtcNow.Ticks, message); file.Flush(); } } - catch (IOException) + catch (Exception e) when (!ExceptionHandling.IsCriticalException(e)) { - // Trace file IO failures must never crash the build engine. - // In multithreaded mode, file contention can occur if multiple engines - // happen to share a trace file path despite the per-node naming. + // Trace file failures must never crash the build engine. + // Matches the defensive pattern used by Scheduler.TraceScheduler. } } } From 1e42ab18c6276da04b10863479e80f9a24eb70dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Provazn=C3=ADk?= Date: Tue, 31 Mar 2026 10:52:21 +0200 Subject: [PATCH 3/7] improve test Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/Build.UnitTests/BackEnd/BuildManager_Tests.cs | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/Build.UnitTests/BackEnd/BuildManager_Tests.cs b/src/Build.UnitTests/BackEnd/BuildManager_Tests.cs index 17a0ae93607..9846c98a1de 100644 --- a/src/Build.UnitTests/BackEnd/BuildManager_Tests.cs +++ b/src/Build.UnitTests/BackEnd/BuildManager_Tests.cs @@ -4635,11 +4635,12 @@ public void MultiThreadedBuild_SharedConfiguration_DoesNotCrash() /// and catches non-critical exceptions so trace failures can never crash the build engine. /// [Fact(Timeout = 30_000)] - public async System.Threading.Tasks.Task MultiThreadedBuild_WithDebugSchedulerTracing_DoesNotDeadlock() + public void MultiThreadedBuild_WithDebugSchedulerTracing_DoesNotDeadlock() { string debugPath = _env.CreateFolder().Path; _env.SetEnvironmentVariable("MSBUILDDEBUGSCHEDULER", "1"); _env.SetEnvironmentVariable("MSBUILDDEBUGPATH", debugPath); + FrameworkDebugUtils.SetDebugPath(debugPath); // Create a root project that builds several independent child projects in parallel. // This forces multiple in-proc nodes to run concurrently, which triggers @@ -4691,6 +4692,17 @@ public async System.Threading.Tasks.Task MultiThreadedBuild_WithDebugSchedulerTr result.OverallResult.ShouldBe(BuildResultCode.Success); _logger.AssertLogContains("Root completed"); + + // Verify that scheduler tracing actually produced at least one non-empty trace file + // in the configured debug directory. + string[] traceFiles = Directory.GetFiles(debugPath, "EngineTrace_*.txt"); + traceFiles.ShouldNotBeEmpty("Expected at least one EngineTrace_*.txt file to be created in the debug directory."); + + bool hasNonEmptyTraceFile = traceFiles + .Select(path => new FileInfo(path)) + .Any(info => info.Length > 0); + + hasNonEmptyTraceFile.ShouldBeTrue("Expected at least one EngineTrace_*.txt file to contain trace data."); } } } From c2b7bbadd522cb7528dfb636e951c76838bdfc69 Mon Sep 17 00:00:00 2001 From: Jan Provaznik Date: Tue, 31 Mar 2026 12:33:46 +0200 Subject: [PATCH 4/7] Fix SetDebugPath call - method takes no arguments FrameworkDebugUtils.SetDebugPath() is parameterless; it reads from the MSBUILDDEBUGPATH environment variable which is already set on the previous line. The incorrect SetDebugPath(debugPath) call caused CS1501 across all CI legs. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/Build.UnitTests/BackEnd/BuildManager_Tests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Build.UnitTests/BackEnd/BuildManager_Tests.cs b/src/Build.UnitTests/BackEnd/BuildManager_Tests.cs index 9846c98a1de..ec22f0fa56f 100644 --- a/src/Build.UnitTests/BackEnd/BuildManager_Tests.cs +++ b/src/Build.UnitTests/BackEnd/BuildManager_Tests.cs @@ -4640,7 +4640,7 @@ public void MultiThreadedBuild_WithDebugSchedulerTracing_DoesNotDeadlock() string debugPath = _env.CreateFolder().Path; _env.SetEnvironmentVariable("MSBUILDDEBUGSCHEDULER", "1"); _env.SetEnvironmentVariable("MSBUILDDEBUGPATH", debugPath); - FrameworkDebugUtils.SetDebugPath(debugPath); + FrameworkDebugUtils.SetDebugPath(); // Create a root project that builds several independent child projects in parallel. // This forces multiple in-proc nodes to run concurrently, which triggers From 951e41c1613430ca6b67e73ed273a857659d352a Mon Sep 17 00:00:00 2001 From: Jan Provaznik Date: Tue, 31 Mar 2026 13:28:44 +0200 Subject: [PATCH 5/7] Log trace file failures via _nodeLoggingContext When a non-critical exception occurs writing the engine trace file, log the failure message and stack trace at Low importance through _nodeLoggingContext (if available) so it appears in diagnostic-level build output. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../BackEnd/Components/BuildRequestEngine/BuildRequestEngine.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Build/BackEnd/Components/BuildRequestEngine/BuildRequestEngine.cs b/src/Build/BackEnd/Components/BuildRequestEngine/BuildRequestEngine.cs index f26a7581064..55e7044ea92 100644 --- a/src/Build/BackEnd/Components/BuildRequestEngine/BuildRequestEngine.cs +++ b/src/Build/BackEnd/Components/BuildRequestEngine/BuildRequestEngine.cs @@ -1582,6 +1582,7 @@ private void TraceEngine(string format, params object[] stuff) { // Trace file failures must never crash the build engine. // Matches the defensive pattern used by Scheduler.TraceScheduler. + _nodeLoggingContext?.LogCommentFromText(MessageImportance.Low, $"Writing Engine trace file failed: {e}"); } } } From 58e5f66f43b098b792e897c517e60ff973eab39a Mon Sep 17 00:00:00 2001 From: Jan Provaznik Date: Tue, 31 Mar 2026 15:51:02 +0200 Subject: [PATCH 6/7] Make timeout test async to satisfy xUnit requirement xUnit only supports Timeout on async tests. Wrap the test body in Task.Run and return async Task. Use fully-qualified Task type to avoid ambiguity with Microsoft.Build.Utilities.Task. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../BackEnd/BuildManager_Tests.cs | 117 +++++++++--------- 1 file changed, 60 insertions(+), 57 deletions(-) diff --git a/src/Build.UnitTests/BackEnd/BuildManager_Tests.cs b/src/Build.UnitTests/BackEnd/BuildManager_Tests.cs index ec22f0fa56f..60b95abb446 100644 --- a/src/Build.UnitTests/BackEnd/BuildManager_Tests.cs +++ b/src/Build.UnitTests/BackEnd/BuildManager_Tests.cs @@ -4635,74 +4635,77 @@ public void MultiThreadedBuild_SharedConfiguration_DoesNotCrash() /// and catches non-critical exceptions so trace failures can never crash the build engine. /// [Fact(Timeout = 30_000)] - public void MultiThreadedBuild_WithDebugSchedulerTracing_DoesNotDeadlock() + public async System.Threading.Tasks.Task MultiThreadedBuild_WithDebugSchedulerTracing_DoesNotDeadlock() { - string debugPath = _env.CreateFolder().Path; - _env.SetEnvironmentVariable("MSBUILDDEBUGSCHEDULER", "1"); - _env.SetEnvironmentVariable("MSBUILDDEBUGPATH", debugPath); - FrameworkDebugUtils.SetDebugPath(); - - // Create a root project that builds several independent child projects in parallel. - // This forces multiple in-proc nodes to run concurrently, which triggers - // concurrent TraceEngine() calls. - const int childCount = 4; - string[] childPaths = new string[childCount]; - - string childContent = CleanupFileContents(""" - - - - - - """); - - for (int i = 0; i < childCount; i++) + await System.Threading.Tasks.Task.Run(() => { - childPaths[i] = _env.CreateFile(".proj").Path; - File.WriteAllText(childPaths[i], childContent); - } + string debugPath = _env.CreateFolder().Path; + _env.SetEnvironmentVariable("MSBUILDDEBUGSCHEDULER", "1"); + _env.SetEnvironmentVariable("MSBUILDDEBUGPATH", debugPath); + FrameworkDebugUtils.SetDebugPath(); + + // Create a root project that builds several independent child projects in parallel. + // This forces multiple in-proc nodes to run concurrently, which triggers + // concurrent TraceEngine() calls. + const int childCount = 4; + string[] childPaths = new string[childCount]; + + string childContent = CleanupFileContents(""" + + + + + + """); - string rootContent = CleanupFileContents($""" - - - - - - - """); + for (int i = 0; i < childCount; i++) + { + childPaths[i] = _env.CreateFile(".proj").Path; + File.WriteAllText(childPaths[i], childContent); + } + + string rootContent = CleanupFileContents($""" + + + + + + + """); - string rootPath = _env.CreateFile(".proj").Path; - File.WriteAllText(rootPath, rootContent); + string rootPath = _env.CreateFile(".proj").Path; + File.WriteAllText(rootPath, rootContent); - var buildParameters = new BuildParameters - { - MaxNodeCount = childCount + 1, - EnableNodeReuse = false, - MultiThreaded = true, - DisableInProcNode = false, - SaveOperatingEnvironment = false, - Loggers = [_logger], - }; + var buildParameters = new BuildParameters + { + MaxNodeCount = childCount + 1, + EnableNodeReuse = false, + MultiThreaded = true, + DisableInProcNode = false, + SaveOperatingEnvironment = false, + Loggers = [_logger], + }; - var data = new BuildRequestData(rootPath, new Dictionary(), null, - ["Build"], null); + var data = new BuildRequestData(rootPath, new Dictionary(), null, + ["Build"], null); - BuildManager.DefaultBuildManager.Dispose(); - BuildResult result = BuildManager.DefaultBuildManager.Build(buildParameters, data); + BuildManager.DefaultBuildManager.Dispose(); + BuildResult result = BuildManager.DefaultBuildManager.Build(buildParameters, data); - result.OverallResult.ShouldBe(BuildResultCode.Success); - _logger.AssertLogContains("Root completed"); + result.OverallResult.ShouldBe(BuildResultCode.Success); + _logger.AssertLogContains("Root completed"); - // Verify that scheduler tracing actually produced at least one non-empty trace file - // in the configured debug directory. - string[] traceFiles = Directory.GetFiles(debugPath, "EngineTrace_*.txt"); - traceFiles.ShouldNotBeEmpty("Expected at least one EngineTrace_*.txt file to be created in the debug directory."); + // Verify that scheduler tracing actually produced at least one non-empty trace file + // in the configured debug directory. + string[] traceFiles = Directory.GetFiles(debugPath, "EngineTrace_*.txt"); + traceFiles.ShouldNotBeEmpty("Expected at least one EngineTrace_*.txt file to be created in the debug directory."); - bool hasNonEmptyTraceFile = traceFiles - .Select(path => new FileInfo(path)) - .Any(info => info.Length > 0); + bool hasNonEmptyTraceFile = traceFiles + .Select(path => new FileInfo(path)) + .Any(info => info.Length > 0); - hasNonEmptyTraceFile.ShouldBeTrue("Expected at least one EngineTrace_*.txt file to contain trace data."); + hasNonEmptyTraceFile.ShouldBeTrue("Expected at least one EngineTrace_*.txt file to contain trace data."); + }); } } } From 8e2a0f4563ff6f6321ed5a146ca12d9b090d12be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Provazn=C3=ADk?= Date: Tue, 31 Mar 2026 17:58:58 +0200 Subject: [PATCH 7/7] Update src/Build/BackEnd/Components/BuildRequestEngine/BuildRequestEngine.cs Co-authored-by: AR-May <67507805+AR-May@users.noreply.github.com> --- .../BackEnd/Components/BuildRequestEngine/BuildRequestEngine.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Build/BackEnd/Components/BuildRequestEngine/BuildRequestEngine.cs b/src/Build/BackEnd/Components/BuildRequestEngine/BuildRequestEngine.cs index 55e7044ea92..27eae7c6f33 100644 --- a/src/Build/BackEnd/Components/BuildRequestEngine/BuildRequestEngine.cs +++ b/src/Build/BackEnd/Components/BuildRequestEngine/BuildRequestEngine.cs @@ -1582,7 +1582,7 @@ private void TraceEngine(string format, params object[] stuff) { // Trace file failures must never crash the build engine. // Matches the defensive pattern used by Scheduler.TraceScheduler. - _nodeLoggingContext?.LogCommentFromText(MessageImportance.Low, $"Writing Engine trace file failed: {e}"); + _nodeLoggingContext?.LogCommentFromText(MessageImportance.Low, $"Failed to write to engine trace file: {e}"); } } }