{"record":{"id":"644d3676ca11b0ae","repo":"HangfireIO/Hangfire","slug":"jobstorage-jobexpirationtimeout-value-should-be-eq","errorCode":null,"errorMessage":"JobStorage.JobExpirationTimeout value should be equal or greater than zero.","messagePattern":"JobStorage\\.JobExpirationTimeout value should be equal or greater than zero\\.","errorType":"exception","errorClass":"ArgumentException","httpStatus":null,"severity":"error","filePath":"src/Hangfire.Core/JobStorage.cs","lineNumber":74,"sourceCode":"            {\n                lock (LockObject)\n                {\n                    _current = value;\n                }\n            }\n        }\n\n        public TimeSpan JobExpirationTimeout\n        {\n            get\n            {\n                return _jobExpirationTimeout;\n            }\n            set\n            {\n                if (value < TimeSpan.Zero)\n                {\n                    throw new ArgumentException(\"JobStorage.JobExpirationTimeout value should be equal or greater than zero.\", nameof(value));\n                }\n\n                _jobExpirationTimeout = value;\n            }\n        }\n\n        public virtual bool LinearizableReads => false;\n\n        public abstract IMonitoringApi GetMonitoringApi();\n\n        public abstract IStorageConnection GetConnection();\n\n        public virtual IStorageConnection GetReadOnlyConnection()\n        {\n            return GetConnection();\n        }\n\n#pragma warning disable 618","sourceCodeStart":56,"sourceCodeEnd":92,"githubUrl":"https://github.com/HangfireIO/Hangfire/blob/c236dd0f930f831ec151e436e138ddc429a02a72/src/Hangfire.Core/JobStorage.cs#L56-L92","documentation":"Thrown by the JobStorage.JobExpirationTimeout setter when the value is a negative TimeSpan. This timeout controls how long completed/failed jobs remain in storage before automatic cleanup; a negative value is logically invalid.","triggerScenarios":"Setting JobStorage.Current.JobExpirationTimeout = TimeSpan.FromMinutes(-5) or passing a negative TimeSpan value. Also occurs when computing the timeout from a configuration value that was parsed as a negative number.","commonSituations":"A misconfigured app setting (e.g., JobExpirationTimeout=-1 in config), an arithmetic error computing the timeout, or a deserialized TimeSpan from a config file with a negative value.","solutions":["Use TimeSpan.Zero to disable expiration delay, or a positive value like TimeSpan.FromDays(1)","Validate the configuration value is non-negative before assigning","Use Math.Max(TimeSpan.Zero, parsedTimespan) as a safety guard"],"exampleFix":"// before\nstorage.JobExpirationTimeout = TimeSpan.FromSeconds(config.TimeoutSeconds);\n// config.TimeoutSeconds is -30\n\n// after\nvar seconds = Math.Max(0, config.TimeoutSeconds);\nstorage.JobExpirationTimeout = TimeSpan.FromSeconds(seconds);","handlingStrategy":"validation","validationCode":"var timeout = TimeSpan.FromSeconds(config.TimeoutSeconds);\nif (timeout < TimeSpan.Zero) timeout = TimeSpan.Zero;\nstorage.JobExpirationTimeout = timeout;","typeGuard":"value >= TimeSpan.Zero","tryCatchPattern":null,"preventionTips":["Use Math.Max(TimeSpan.Zero, value) when computing timeouts from configuration","Validate config values for timeout are non-negative at application startup","Use TimeSpan.Zero to keep jobs indefinitely, not negative values"],"tags":["argument-exception","job-storage","configuration","validation","hangfire"],"backgroundTag":null,"analyzedSha":"c236dd0f930f831ec151e436e138ddc429a02a72","analyzedAt":"2026-08-13T20:27:11.027Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}