{"record":{"id":"e37751d12e0870f6","repo":"dotnet/wpf","slug":"sr-animation-keytime-lessthanzero","errorCode":null,"errorMessage":"SR.Animation_KeyTime_LessThanZero","messagePattern":"SR\\.Animation_KeyTime_LessThanZero","errorType":"exception","errorClass":"ArgumentOutOfRangeException","httpStatus":null,"severity":"error","filePath":"src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/Animation/KeyTime.cs","lineNumber":50,"sourceCode":"\n            KeyTime keyTime = new KeyTime\n            {\n                _value = percent,\n                _type = KeyTimeType.Percent\n            };\n\n            return keyTime;\n        }\n\n        /// <summary>\n        /// \n        /// </summary>\n        /// <param name=\"timeSpan\"></param>\n        public static KeyTime FromTimeSpan(TimeSpan timeSpan)\n        {\n            if (timeSpan < TimeSpan.Zero)\n            {\n                throw new ArgumentOutOfRangeException(nameof(timeSpan), SR.Format(SR.Animation_KeyTime_LessThanZero, timeSpan));\n            }\n\n            KeyTime keyTime = new KeyTime\n            {\n                _value = timeSpan,\n                _type = KeyTimeType.TimeSpan\n            };\n\n            return keyTime;\n        }\n\n        /// <summary>\n        /// \n        /// </summary>\n        /// <value></value>\n        public static KeyTime Uniform\n        {\n            get","sourceCodeStart":32,"sourceCodeEnd":68,"githubUrl":"https://github.com/dotnet/wpf/blob/81131a70a4c573cd62748a5c36908fc4d662daa9/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/Animation/KeyTime.cs#L32-L68","documentation":"KeyTime.FromTimeSpan throws ArgumentOutOfRangeException (SR.Animation_KeyTime_LessThanZero) because a TimeSpan KeyTime marks an offset from the start of the animation and cannot be negative. Only zero or positive durations are accepted.","triggerScenarios":"KeyTime.FromTimeSpan(ts) where ts < TimeSpan.Zero — e.g. subtracting timestamps to compute a key offset and getting a negative result.","commonSituations":"Computing key times from measured event times where ordering assumptions broke; user config with negative offsets; arithmetic on durations where a later value was subtracted from an earlier one.","solutions":["Clamp negative spans to zero before calling: if (ts < TimeSpan.Zero) ts = TimeSpan.Zero.","Fix the calculation that produced the negative TimeSpan (guard ordering: Math.Max(0, elapsed)).","Validate configured/serialized offsets for negativity before constructing key frames.","Catch ArgumentOutOfRangeException and substitute KeyTime.FromTimeSpan(TimeSpan.Zero)."],"exampleFix":"// before\nvar kt = KeyTime.FromTimeSpan(end - start); // may be negative\n// after\nvar delta = end - start;\nvar kt = KeyTime.FromTimeSpan(delta < TimeSpan.Zero ? TimeSpan.Zero : delta);","handlingStrategy":"validation","validationCode":"if (timeSpan < TimeSpan.Zero)\n    timeSpan = TimeSpan.Zero;\nvar kt = KeyTime.FromTimeSpan(timeSpan);","typeGuard":"static TimeSpan NonNegative(TimeSpan t) => t < TimeSpan.Zero ? TimeSpan.Zero : t;","tryCatchPattern":"try { kt = KeyTime.FromTimeSpan(delta); }\ncatch (ArgumentOutOfRangeException)\n{ kt = KeyTime.FromTimeSpan(TimeSpan.Zero); }","preventionTips":["Guard timestamp subtraction so later-minus-earlier cannot go negative","Validate serialized offsets for negativity before building key frames","Use Math.Max(TimeSpan.Zero, delta) on all derived durations","Reject negative offsets in config parsing with a clear app-level message"],"tags":["wpf","animation","keytime","timespan"],"backgroundTag":"argument-out-of-range","analyzedSha":"81131a70a4c573cd62748a5c36908fc4d662daa9","analyzedAt":"2026-09-14T10:12:48.479Z","contentChangedAt":"2026-09-14T10:12:48.479Z","schemaVersion":2},"datasetVersion":"2026-09-21T21:30:21.729Z"}