{"record":{"id":"2b958cb72db201f5","repo":"HangfireIO/Hangfire","slug":"the-timeout-value-must-be-positive","errorCode":null,"errorMessage":"The `timeOut` value must be positive.","messagePattern":"The `timeOut` value must be positive\\.","errorType":"validation","errorClass":"ArgumentException","httpStatus":null,"severity":"error","filePath":"src/Hangfire.SqlServer/SqlServerConnection.cs","lineNumber":571,"sourceCode":"                var affected = connection.Execute(\n                    query,\n                    new { id = serverId },\n                    commandTimeout: storage.CommandTimeout);\n\n                if (affected == 0)\n                {\n                    throw new BackgroundServerGoneException();\n                }\n\n                return affected;\n            }, serverId);\n        }\n\n        public override int RemoveTimedOutServers(TimeSpan timeOut)\n        {\n            if (timeOut.Duration() != timeOut)\n            {\n                throw new ArgumentException(\"The `timeOut` value must be positive.\", nameof(timeOut));\n            }\n\n            return _storage.UseConnection(_dedicatedConnection, static (storage, connection, timeout) => connection.Execute(\n                storage.GetQueryFromTemplate(static schemaName =>\n                    $@\"delete s from [{schemaName}].Server s with (readpast, readcommitted) where LastHeartbeat < dateadd(ms, @timeoutMsNeg, sysutcdatetime())\"),\n                new { timeoutMsNeg = timeout.Negate().TotalMilliseconds },\n                commandTimeout: storage.CommandTimeout), timeOut);\n        }\n\n        public override long GetSetCount(string key)\n        {\n            if (key == null) throw new ArgumentNullException(nameof(key));\n\n            return _storage.UseConnection(_dedicatedConnection, static (storage, connection, key) => connection.ExecuteScalar<long>(\n                storage.GetQueryFromTemplate(static schemaName =>\n                    $@\"select count(*) from [{schemaName}].[Set] with (forceseek) where [Key] = @key\"),\n                new { key = key },\n                commandTimeout: storage.CommandTimeout), key);","sourceCodeStart":553,"sourceCodeEnd":589,"githubUrl":"https://github.com/HangfireIO/Hangfire/blob/c236dd0f930f831ec151e436e138ddc429a02a72/src/Hangfire.SqlServer/SqlServerConnection.cs#L553-L589","documentation":"ArgumentException thrown by SqlServerConnection.RemoveTimedOutServers when the provided timeOut is not equal to its own Duration() — i.e. it is negative. The cleanup deletes Server rows whose LastHeartbeat is older than now - timeOut; a negative timeOut would invert the logic (deleting active servers), so Hangfire rejects it up front.","triggerScenarios":"Calling RemoveTimedOutServers with a negative TimeSpan (or calling .Negate() unintentionally before passing it).","commonSituations":"Computing timeOut from a config value that defaulted to a negative number; subtracting instead of adding; passing -configuredTimeout by mistake; reading a malformed setting.","solutions":["Pass a positive TimeSpan (e.g. TimeSpan.FromMinutes(5)) to RemoveTimedOutServers.","Validate the configured timeout at startup: if (timeout < TimeSpan.Zero) throw a clear config error.","Guard with TimeSpan.Max(TimeSpan.Zero, timeout) when deriving the value arithmetically."],"exampleFix":"// before\nstorage.RemoveTimedOutServers(now - recordedAt);\n\n// after\nstorage.RemoveTimedOutServers(TimeSpan.FromMinutes(5));","handlingStrategy":"validation","validationCode":"static TimeSpan AssertPositiveTimeout(TimeSpan t)\n{\n    if (t.Duration() != t) throw new ArgumentException(\"timeOut must be positive.\", nameof(t));\n    return t;\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Validate timeout config values at startup.","Use named constants (e.g. ServerTimeout) instead of arithmetic to avoid sign mistakes.","Unit-test RemoveTimedOutServers callers with negative inputs."],"tags":["sqlserver","argument","server-lifecycle"],"backgroundTag":null,"analyzedSha":"c236dd0f930f831ec151e436e138ddc429a02a72","analyzedAt":"2026-08-13T20:27:11.027Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}