diff --git a/src/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer/OtOpcUaNodeManager.cs b/src/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer/OtOpcUaNodeManager.cs index 2edbadda..92669fc3 100644 --- a/src/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer/OtOpcUaNodeManager.cs +++ b/src/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer/OtOpcUaNodeManager.cs @@ -1902,7 +1902,9 @@ public sealed class OtOpcUaNodeManager : CustomNodeManager2 // The over-fetch cap MUST be explicit and non-zero: a cap of 0 falls back to the backend's // MaxValuesPerRead, which would re-introduce the very stall we're escaping. +1 over the bound // lets us DETECT a cluster strictly larger than the bound (the absurd-burst backstop below). - var overfetchCap = (uint)(MaxTieClusterOverfetch + 1); + // Compute in uint so +1 can never wrap: Math.Max(1,…) also guards against a zero/negative + // config value slipping through (Validate() warns but does not block startup). + var overfetchCap = (uint)Math.Max(1, MaxTieClusterOverfetch) + 1u; var cluster = HistorianDataSource .ReadRawAsync(tagname, startUtc, startUtc, overfetchCap, CancellationToken.None) .GetAwaiter().GetResult().Samples; diff --git a/src/Server/ZB.MOM.WW.OtOpcUa.Runtime/Historian/ServerHistorianOptions.cs b/src/Server/ZB.MOM.WW.OtOpcUa.Runtime/Historian/ServerHistorianOptions.cs index 96908f43..572ce05e 100644 --- a/src/Server/ZB.MOM.WW.OtOpcUa.Runtime/Historian/ServerHistorianOptions.cs +++ b/src/Server/ZB.MOM.WW.OtOpcUa.Runtime/Historian/ServerHistorianOptions.cs @@ -63,6 +63,9 @@ public sealed class ServerHistorianOptions warnings.Add("ServerHistorian:SharedSecret is empty while the historian is enabled — the Wonderware sidecar Hello frame will carry an empty secret."); if (Port <= 0) warnings.Add($"ServerHistorian:Port is {Port} — must be > 0; the read client cannot dial the sidecar."); + // MaxTieClusterOverfetch is intentionally checked AFTER the Enabled early-return above: + // the over-fetch code path only runs when a real IHistorianDataSource is wired in, + // so a zero/negative value is harmless (and noise-free) when the historian is disabled. if (MaxTieClusterOverfetch <= 0) warnings.Add($"ServerHistorian:MaxTieClusterOverfetch is {MaxTieClusterOverfetch} — must be > 0; HistoryRead-Raw cannot page within an oversized tie cluster and will surface BadHistoryOperationUnsupported for those reads."); return warnings;