{"record":{"id":"644b7c6aeb27f7d1","repo":"dotnet/wpf","slug":"sr-timing-nottimespan","errorCode":null,"errorMessage":"SR.Timing_NotTimeSpan","messagePattern":"SR\\.Timing_NotTimeSpan","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Duration.cs","lineNumber":395,"sourceCode":"        /// <value>A Duration that represents a Forever value.</value>\n        public static Duration Forever\n        {\n            get\n            {\n                return new Duration(DurationType.Forever);\n            }\n        }\n\n        /// <summary>\n        /// Returns the TimeSpan value that this Duration represents.\n        /// </summary>\n        /// <value>The TimeSpan value that this Duration represents.</value>\n        /// <exception cref=\"InvalidOperationException\">Thrown if this Duration represents null.</exception>\n        public TimeSpan TimeSpan\n        {\n            get\n            {\n                return HasTimeSpan ? _timeSpan : throw new InvalidOperationException(SR.Format(SR.Timing_NotTimeSpan, this));\n            }\n        }\n\n        #endregion\n\n        #region Methods\n\n        /// <summary>\n        /// Adds the specified Duration to this instance.\n        /// </summary>\n        /// <param name=\"duration\"></param>\n        /// <returns>A Duration that represents the value of this instance plus the value of duration.</returns>\n        public Duration Add(Duration duration)\n        {\n            return this + duration;\n        }\n\n        /// <summary>","sourceCodeStart":377,"sourceCodeEnd":413,"githubUrl":"https://github.com/dotnet/wpf/blob/81131a70a4c573cd62748a5c36908fc4d662daa9/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Duration.cs#L377-L413","documentation":"Duration.TimeSpan throws InvalidOperationException when the Duration instance does not hold a TimeSpan value (e.g. it is Duration.Automatic or Duration.Forever). The WPF Duration type is a union of a TimeSpan, Automatic, and Forever states, and this accessor is only valid for the TimeSpan state. The library throws to force callers to check HasTimeSpan before unwrapping the value.","triggerScenarios":"Accessing the .TimeSpan property on a Duration whose HasTimeSpan is false — e.g. `Duration.Forever.TimeSpan`, `Duration.Automatic.TimeSpan`, or a Duration built via Duration.Automatic/Forever or the Duration(DurationType) constructor.","commonSituations":"Animation code reading a Duration that came from XAML set to \"Automatic\" or \"Forever\"; interop code assuming all Durations are finite; defaults set to Duration.Automatic then blindly read back.","solutions":["Check the HasTimeSpan property before reading .TimeSpan","Handle Duration.Forever and Duration.Automatic explicitly in branching logic","If a finite default is required, normalize: use duration.HasTimeSpan ? duration.TimeSpan : someFallback"],"exampleFix":"// before\nTimeSpan ts = storyboard.Duration.TimeSpan;\n// after\nif (storyboard.Duration.HasTimeSpan)\n    TimeSpan ts = storyboard.Duration.TimeSpan;\nelse\n    TimeSpan ts = TimeSpan.FromSeconds(1); // fallback for Automatic/Forever","handlingStrategy":"validation","validationCode":"if (duration != null && duration.HasTimeSpan) { var ts = duration.TimeSpan; }","typeGuard":"bool HasFiniteDuration(Duration d) => d != null && d.HasTimeSpan;","tryCatchPattern":"try { var ts = d.TimeSpan; } catch (InvalidOperationException) { /* Automatic/Forever: use fallback */ }","preventionTips":["Always gate .TimeSpan access behind HasTimeSpan","Treat Duration.Automatic/Forever as distinct states in branch logic","Add a GetTimeSpanOrFallback helper in shared animation code"],"tags":["wpf","animation","duration","invalid-operation"],"backgroundTag":"unsupported-operation","analyzedSha":"81131a70a4c573cd62748a5c36908fc4d662daa9","analyzedAt":"2026-09-14T10:12:48.479Z","contentChangedAt":"2026-09-14T10:12:48.479Z","schemaVersion":2},"datasetVersion":"2026-09-22T01:17:13.364Z"}