dotnet/wpf · error · ArgumentOutOfRangeException

Stream length cannot be negative.

Error message

Stream length cannot be negative.

What it means

RightsManagementEncryptedStream.SetLength validates that the requested new length is non-negative before updating the cached length. A negative length has no meaning for a stream, so the API throws ArgumentOutOfRangeException with SR.CannotMakeStreamLengthNegative. Write() and other size-affecting operations funnel through this method.

Solutions

  1. Validate newLength >= 0 before calling SetLength and correct or reject the caller-supplied value.
  2. Clamp with long safeLength = Math.Max(0, newLength); before invoking SetLength.
  3. If the length originates from parsed metadata, validate it at parse time (e.g. use checked arithmetic / reject negatives) instead of propagating it to the stream.
  4. If the intent was truncation of only a portion, recompute the delta between current and target lengths explicitly.
  5. Catch ArgumentOutOfRangeException around SetLength when lengths come from external data and recover by re-opening the stream.

Example fix

// before
stream.SetLength(requestedLength); // requestedLength may be < 0
// after
if (requestedLength < 0)
    throw new ArgumentException("computed length must be >= 0", nameof(requestedLength));
stream.SetLength(Math.Max(0, requestedLength));
Defensive patterns

Strategy: validation

Validate before calling

if (newLength < 0)
    throw new ArgumentException("newLength must be >= 0", nameof(newLength));
stream.SetLength(newLength);

Type guard

bool IsValidSetLength(long newLength) => newLength >= 0 && newLength <= long.MaxValue;

Try / catch

try { stream.SetLength(newLength); }
catch (ArgumentOutOfRangeException) { newLength = Math.Max(0, newLength); stream.SetLength(newLength); }

Prevention

When it happens

Trigger: Calling SetLength(negativeValue) directly; a Write() call whose computed end position resolves to a negative length due to a bad buffer/position calculation; passing untrusted parsed lengths through to SetLength.

Common situations: Applying lengths parsed from a corrupted package file; off-by-one or sign errors when computing truncation sizes; wrapping this stream in code that derives newLength from signed arithmetic that underflows.

Related errors


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

Appendix: source

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

            if (temp < 0)
            {
                throw new ArgumentOutOfRangeException(nameof(offset), SR.SeekNegative);
            }

            _streamPosition = temp;
            return _streamPosition;
        }        

        /// <summary>
        /// See .NET Framework SDK under System.IO.Stream
        /// </summary>
        public override void SetLength(long newLength)
        {
            CheckDisposed(); 
            
            if (newLength < 0)
            {
                throw new ArgumentOutOfRangeException(nameof(newLength), SR.CannotMakeStreamLengthNegative);
            }

            _streamCachedLength = newLength;

            // We are not caching this transaction for the following reason. The extra data that might 
            // be added to stream when the new length is higher than the existing length, 
            // although undefined (could be junk) must be consistent. Consistent 
            // is defined in a sense of multiple read requests performed on the same stream area.
            // In order to guarantee this consistency we either have to come up with some initial value 
            // (0 or anything else) remember the initialized area (or multiple areas like that if get a set 
            // of non contiguous writes), and take it into account during all the transactions.
            // Alternatively we can get some real bits allocated on the baseStream and take advantage 
            // of the underlying stream capability to preserve consistent content of the extra bits being 
            // allocated here.  
            FlushLength();

            if (_streamPosition > Length)
            {

View on GitHub (pinned to 81131a70a4)