{"record":{"id":"50f17ee927ca015c","repo":"dotnet/machinelearning","slug":"strings-spansmultiplebuffers-50f17e","errorCode":null,"errorMessage":"Strings.SpansMultipleBuffers","messagePattern":"Strings\\.SpansMultipleBuffers","errorType":"exception","errorClass":"ArgumentException","httpStatus":null,"severity":"error","filePath":"src/Microsoft.Data.Analysis/PrimitiveDataFrameColumn.cs","lineNumber":136,"sourceCode":"        private int GetNullCount(long startIndex, int numberOfRows)\n        {\n            int nullCount = 0;\n            for (long i = startIndex; i < numberOfRows; i++)\n            {\n                if (!IsValid(i))\n                    nullCount++;\n            }\n            return nullCount;\n        }\n\n        protected internal override Apache.Arrow.Array ToArrowArray(long startIndex, int numberOfRows)\n        {\n            int bufferIndex = numberOfRows == 0 ? 0 : _columnContainer.GetIndexOfBufferContainingRowIndex(startIndex);\n            int offset = (int)(startIndex - bufferIndex * ReadOnlyDataFrameBuffer<T>.MaxCapacity);\n\n            if (numberOfRows != 0 && numberOfRows > _columnContainer.Buffers[bufferIndex].Length - offset)\n            {\n                throw new ArgumentException(Strings.SpansMultipleBuffers, nameof(numberOfRows));\n            }\n\n            int nullCount = GetNullCount(startIndex, numberOfRows);\n\n            //DateTime requires convertion\n            if (this.DataType == typeof(DateTime))\n            {\n                if (numberOfRows == 0)\n                    return new Date64Array(ArrowBuffer.Empty, ArrowBuffer.Empty, numberOfRows, nullCount, offset);\n\n                ReadOnlyDataFrameBuffer<T> valueBuffer = (numberOfRows == 0) ? null : _columnContainer.Buffers[bufferIndex];\n                ReadOnlyDataFrameBuffer<byte> nullBuffer = (numberOfRows == 0) ? null : _columnContainer.NullBitMapBuffers[bufferIndex];\n\n                ReadOnlySpan<DateTime> valueSpan = MemoryMarshal.Cast<T, DateTime>(valueBuffer.ReadOnlySpan);\n                Date64Array.Builder builder = new Date64Array.Builder().Reserve(valueBuffer.Length);\n\n                for (int i = 0; i < valueBuffer.Length; i++)\n                {","sourceCodeStart":118,"sourceCodeEnd":154,"githubUrl":"https://github.com/dotnet/machinelearning/blob/7b76e69cf964daeca3f1377af6bc5543284d56c6/src/Microsoft.Data.Analysis/PrimitiveDataFrameColumn.cs#L118-L154","documentation":"PrimitiveDataFrameColumn<T>.ToArrowArray throws ArgumentException with the message Strings.SpansMultipleBuffers when the requested [startIndex, numberOfRows] slice is not contained within a single internal ReadOnlyDataFrameBuffer. Arrow arrays must be contiguous, so a range that would cross a buffer boundary (buffer capacity is ReadOnlyDataFrameBuffer<T>.MaxCapacity) is rejected via nameof(numberOfRows).","triggerScenarios":"Calling ToArrowArray(startIndex, numberOfRows) where numberOfRows exceeds the remaining length of the buffer that contains startIndex, i.e. startIndex + numberOfRows crosses a MaxCapacity boundary while numberOfRows != 0.","commonSituations":"Exporting large columns (over one buffer capacity) to Arrow with slices computed without regard to internal buffer boundaries; custom record-batch writers choosing oversized batch lengths; using GetMaxRecordBatchLength incorrectly.","solutions":["Clamp numberOfRows so startIndex + numberOfRows stays within the containing buffer: numberOfRows = min(numberOfRows, bufferLength - offset)","Use GetMaxRecordBatchLength(startIndex) to pick a batch size that does not span buffers","Split the export into multiple Arrow arrays, one per buffer, and concatenate at the consumer level","Call ToArrowArray with numberOfRows == 0 only for empty arrays; avoid mixing zero and boundary-crossing requests"],"exampleFix":"// before\nvar array = column.ToArrowArray(startIndex, numberOfRows); // may span buffers\n// after\nvar maxLen = column.GetMaxRecordBatchLength(startIndex);\nvar array = column.ToArrowArray(startIndex, Math.Min(numberOfRows, (int)maxLen));","handlingStrategy":"validation","validationCode":"long maxBatch = column.GetMaxRecordBatchLength(startIndex);\nint safeRows = (int)Math.Min(numberOfRows, maxBatch);\nvar array = column.ToArrowArray(startIndex, safeRows);","typeGuard":null,"tryCatchPattern":"try { return column.ToArrowArray(startIndex, numberOfRows); }\ncatch (ArgumentException ex) when (ex.ParamName == nameof(PrimitiveDataFrameColumn<int>.ToArrowArray) && ex.Message.Contains(\"buffers\")) { numberOfRows = (int)column.GetMaxRecordBatchLength(startIndex); return column.ToArrowArray(startIndex, numberOfRows); }","preventionTips":["Always size batches with GetMaxRecordBatchLength(startIndex)","Never request ranges that cross ReadOnlyDataFrameBuffer MaxCapacity boundaries","Compute numberOfRows as bufferLength - offset when exporting within one buffer"],"tags":["argument","arrow","buffer-boundary","dataframe"],"backgroundTag":"invalid-argument-value","analyzedSha":"7b76e69cf964daeca3f1377af6bc5543284d56c6","analyzedAt":"2026-09-11T12:35:38.930Z","contentChangedAt":"2026-09-11T12:35:38.930Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}