diff --git a/Engine/Engine.cs b/Engine/Engine.cs
index 691d8db248c9..d207b3cadb70 100644
--- a/Engine/Engine.cs
+++ b/Engine/Engine.cs
@@ -381,7 +381,7 @@ public void Run(AlgorithmNodePacket job, AlgorithmManager manager, string assemb
// Algorithm runtime error:
if (algorithm.RunTimeError != null)
{
- HandleAlgorithmError(job, algorithm.RunTimeError);
+ HandleAlgorithmError(job, algorithm, algorithm.RunTimeError);
}
// notify the LEAN manager that the algorithm has finished
@@ -477,13 +477,18 @@ public void Run(AlgorithmNodePacket job, AlgorithmManager manager, string assemb
/// Handle an error in the algorithm.Run method.
///
/// Job we're processing
+ /// The algorithm instance that raised the error
/// Error from algorithm stack
- private void HandleAlgorithmError(AlgorithmNodePacket job, Exception err)
+ private void HandleAlgorithmError(AlgorithmNodePacket job, IAlgorithm algorithm, Exception err)
{
AlgorithmHandlers.DataFeed?.Exit();
if (AlgorithmHandlers.Results != null)
{
var message = $"Runtime Error: {err.Message}";
+ if (TryGetOutOfMemoryErrorDetails(job, algorithm, err, out var outOfMemoryDetails))
+ {
+ message += outOfMemoryDetails;
+ }
Log.Trace("Engine.Run(): Sending runtime error to user...");
AlgorithmHandlers.Results.LogMessage(message);
@@ -495,6 +500,42 @@ private void HandleAlgorithmError(AlgorithmNodePacket job, Exception err)
}
}
+ ///
+ /// Checks whether the given exception is an ,
+ /// producing details about the algorithm state and the common causes to be appended to the runtime error message
+ ///
+ /// Job we're processing
+ /// The algorithm instance that raised the error
+ /// Error from algorithm stack
+ /// The out of memory details, null if the error is not an out of memory error
+ /// True if the error is an out of memory error
+ private static bool TryGetOutOfMemoryErrorDetails(AlgorithmNodePacket job, IAlgorithm algorithm, Exception err, out string details)
+ {
+ details = null;
+ if (err is not OutOfMemoryException)
+ {
+ return false;
+ }
+
+ details = Invariant($" The algorithm exhausted its {job.RamAllocation}MB of RAM.");
+ if (algorithm != null)
+ {
+ try
+ {
+ details += Invariant($" State: {algorithm.Securities.Count} securities, {algorithm.SubscriptionManager.Count} subscriptions, {algorithm.UniverseManager.Count} universes.");
+ }
+ catch (Exception stateException)
+ {
+ // best effort: don't let diagnostics collection replace the original error
+ Log.Error(stateException);
+ }
+ }
+ details += " Common causes: universe/subscription count too high for the allocated RAM; unbounded buffers such as rolling windows," +
+ " consolidators or accumulated history results. Fixes: reduce universe size/subscriptions, use coarser resolutions," +
+ " or bound buffers.";
+ return true;
+ }
+
///
/// Load the history provider from the Composer
///