dotnet/wpf · error · ArgumentOutOfRangeException

SR.SeekNegative

Error message

SR.SeekNegative

What it means

CFStream.Seek throws ArgumentOutOfRangeException with SR.SeekNegative when seeking from SeekOrigin.Begin with a negative offset. Positions relative to the beginning of a stream cannot be negative, so the library rejects the call up front instead of passing it to the underlying compound-file IStream. It is a caller contract violation, not a stream-state problem.

Solutions

  1. Ensure the offset passed to Seek with SeekOrigin.Begin is >= 0 before calling
  2. If seeking backwards relative to the current position, use SeekOrigin.Current with a negative offset instead of SeekOrigin.Begin
  3. Clamp computed absolute positions: long pos = Math.Max(0, computedPos);
  4. Catch ArgumentOutOfRangeException at the call site to detect bad position arithmetic

Example fix

// before
stream.Seek(-headerSize, SeekOrigin.Begin);
// after
long target = stream.Length - headerSize;
stream.Seek(Math.Max(0, target), SeekOrigin.Begin);
Defensive patterns

Strategy: validation

Validate before calling

if (offset < 0 && origin == SeekOrigin.Begin) throw new ArgumentException("Begin-seek offset must be >= 0", nameof(offset));

Type guard

static bool IsValidBeginSeek(long offset) => offset >= 0;

Try / catch

try { stream.Seek(offset, SeekOrigin.Begin); } catch (ArgumentOutOfRangeException ex) { /* fix offset math */ }

Prevention

When it happens

Trigger: Calling Seek(offset, SeekOrigin.Begin) on a CompoundFile CFStream with offset < 0, e.g. stream.Seek(-10, SeekOrigin.Begin). Seeks from Current or End with negative offsets are allowed and validated later.

Common situations: Arithmetic computing a target position from Current goes negative and the code is rewritten to use Begin; absolute position variables that were never clamped to >= 0; porting code that used MemoryStream (which throws similar errors) but computing offsets differently for compound files.

Related errors


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

Appendix: source

Thrown at src/Microsoft.DotNet.Wpf/src/WindowsBase/MS/Internal/IO/Packaging/CompoundFile/CFStream.cs:159

    {
        CheckDisposedStatus();

        if (!CanSeek)
        {
            throw new NotSupportedException(SR.SeekNotSupported);
        }
        
        // 
        long seekPos = 0;
        int translatedSeekOrigin = 0;

        switch(origin)
        {
            case SeekOrigin.Begin:
                translatedSeekOrigin = SafeNativeCompoundFileConstants.STREAM_SEEK_SET;
                if( 0 > offset )
                {
                    throw new ArgumentOutOfRangeException(nameof(offset),
                        SR.SeekNegative);
                }
                break;
            case SeekOrigin.Current:
                translatedSeekOrigin = SafeNativeCompoundFileConstants.STREAM_SEEK_CUR;
                // Need to find the current seek pointer to see if we'll end
                //  up with a negative position.
                break;
            case SeekOrigin.End:
                translatedSeekOrigin = SafeNativeCompoundFileConstants.STREAM_SEEK_END;
                // Need to find the current seek pointer to see if we'll end
                //  up with a negative position.
                break;
            default:
                throw new System.ComponentModel.InvalidEnumArgumentException("origin", (int) origin, typeof(SeekOrigin));
        }

        _safeIStream.Seek( offset, translatedSeekOrigin, out seekPos );

View on GitHub (pinned to 81131a70a4)