dotnet/wpf · error · InvalidOperationException

Timing_SeekDestinationNegative

Timing_SeekDestinationNegative

Error message

SR.Timing_SeekDestinationNegative (Timing_SeekDestinationNegative)

What it means

ClockController.Seek computes the absolute destination time and rejects negative results. A negative offset (e.g. seeking before the timeline's start) is not a representable clock time, so WPF throws InvalidOperationException (Timing_SeekDestinationNegative).

Solutions

  1. Clamp the computed offset: Math.Max(offset, TimeSpan.Zero)
  2. Validate the target time before calling Seek and skip the call if negative
  3. When seeking relative to Duration, ensure offset magnitude does not exceed the duration

Example fix

// before
controller.Seek(elapsed - rewindAmount, TimeSeekOrigin.Begin); // throws if negative
// after
var target = elapsed - rewindAmount;
controller.Seek(target < TimeSpan.Zero ? TimeSpan.Zero : target, TimeSeekOrigin.Begin);
Defensive patterns

Strategy: validation

Validate before calling

if (offset < TimeSpan.Zero) offset = TimeSpan.Zero;
controller.Seek(offset, origin);

Try / catch

try { controller.Seek(offset, origin); }
catch (InvalidOperationException ex) when (offset < TimeSpan.Zero) { controller.Seek(TimeSpan.Zero, origin); }

Prevention

When it happens

Trigger: controller.Seek(negativeTimeSpan, TimeSeekOrigin.Begin), or Seek(offset, TimeSeekOrigin.Duration) where offset is negative and larger than the resolved duration (offset + duration < 0).

Common situations: Computed seek targets from user input, playback scrubbing, or bookmark/progress arithmetic that can go below zero (e.g. rewinding further than elapsed time).

Related errors


AI-assisted analysis of dotnet/wpf@81131a70a4 (2026-09-14). Data as JSON: /api/errors/5ca8324335dd8417. Report an issue: GitHub.

Appendix: source

Thrown at src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/Animation/ClockController.cs:179

                Duration duration = _owner.ResolvedDuration;

                if (!duration.HasTimeSpan)
                {
                    // Can't seek relative to the Duration if it has been specified as Forever or if
                    // it has not yet been resolved.
                    throw new InvalidOperationException(SR.Timing_SeekDestinationIndefinite);
                }
                else
                {
                    offset += duration.TimeSpan;
                }
            }

            // Any offset greater than zero is OK here. If it's past the effective
            // duration it means execute the FillBehavior.
            if (offset < TimeSpan.Zero)
            {
                throw new InvalidOperationException(SR.Timing_SeekDestinationNegative);
            }

            _owner.InternalSeek(offset);
        }

        /// <summary>
        /// Process all information that occured until now
        /// </summary>

        public void SeekAlignedToLastTick(TimeSpan offset, TimeSeekOrigin origin)
        {
            // IF YOU CHANGE THIS CODE:
            // This code is very similar to that in Seek and is duplicated
            // in each method so that exceptions will be thrown from the public 
            // method the user has called. You probably need to change both methods.

            if (!TimeEnumHelper.IsValidTimeSeekOrigin(origin))
            {

View on GitHub (pinned to 81131a70a4)