microsoft/FASTER · error · InvalidDataException
wrong amount of data received from page blob, expected=
Error message
wrong amount of data received from page blob, expected={length}, actual={stream.Position} What it means
AzureStorageDevice reads a range of bytes from an Azure page blob into a stream and validates that the stream received exactly offset+length bytes. This InvalidDataException is thrown when the copy from the HTTP response completed with fewer (or more) bytes than requested, indicating truncated or corrupted blob data. The library throws it because silently returning short reads would corrupt log replay.
Solutions
- Verify the blob exists and is at least offset+length bytes before reading; restore from backup if truncated.
- Check that no other process is deleting/truncating blobs (lifecycle policies, competing instances) and that the container is not being emptied.
- Retry the read on transient network failures; ensure Azure Storage retry policy is enabled.
- Confirm the offset/length passed to the read matches the checkpoint metadata written earlier.
Example fix
// before: reading a range that may exceed blob length long length = endOffset - offset; // may exceed blob size await device.ReadAsync(offset, buffer, length); // after: clamp the read to the actual blob size var props = await blob.GetPropertiesAsync(); long length = Math.Min(endOffset, props.Value.ContentLength) - offset; await device.ReadAsync(offset, buffer, length);
Defensive patterns
Strategy: retry
Validate before calling
var props = await blob.GetPropertiesAsync();
if (props.Value.ContentLength < offset + length)
throw new InvalidOperationException($"blob too short: need {offset + length}, have {props.Value.ContentLength}"); Type guard
static bool IsBlobReadShort(Stream s, long offset, long length) => s.Position != offset + length;
Try / catch
try
{
await device.ReadAsync(offset, buffer, length);
}
catch (InvalidDataException ex) when (ex.Message.StartsWith("wrong amount of data received from page blob"))
{
// log, verify blob integrity, optionally retry or restore from checkpoint
} Prevention
- Validate blob length against expected checkpoint size before reading.
- Ensure Azure Storage retry policy is enabled for transient network faults.
- Prevent competing processes/lifecycle rules from deleting or truncating blobs.
- Persist and verify checkpoint metadata (lengths) after every checkpoint.
When it happens
Trigger: Calling the page-blob read path (used by Faster's Azure storage device during checkpoint/log reads) when the blob was resized/truncated, the blob was deleted or leased by another process mid-read, the requested [offset, offset+length) range extends past the blob's committed length, or a transient network failure cut the response body short.
Common situations: Reading a FASTER checkpoint whose blob was truncated by a failed upload; a container/blob deleted by lifecycle policy while the device was running; requesting a byte range beyond the blob size after an improper shutdown; intermittent Azure Storage network failures.
Related errors
- Page read from storage failed, skipping page. Inner…
- Error reading from log file
- Error writing to log file
- Error creating log file for
- Error reading page from device
AI-assisted analysis of microsoft/FASTER@321d872eab (2026-09-15).
Data as JSON: /api/errors/0dd75f0335c8baaf.
Report an issue: GitHub.
Appendix: source
Thrown at cs/src/devices/AzureStorageDevice/AzureStorageDevice.cs:606
}
if (length > 0)
{
var client = (numAttempts > 1 || length == MAX_DOWNLOAD_SIZE) ? blob.Default : blob.Aggressive;
var response = await client.DownloadStreamingAsync(
range: new Azure.HttpRange(sourceAddress + offset, length),
conditions: null,
rangeGetContentHash: false,
cancellationToken: this.StorageErrorHandler.Token)
.ConfigureAwait(false);
await response.Value.Content.CopyToAsync(stream).ConfigureAwait(false);
}
if (stream.Position != offset + length)
{
throw new InvalidDataException($"wrong amount of data received from page blob, expected={length}, actual={stream.Position}");
}
return length;
});
readLength -= length;
offset += length;
}
}
}
void TryWriteAsync(BlobEntry blobEntry, IntPtr sourceAddress, ulong destinationAddress, uint numBytesToWrite, long id)
{
// If pageBlob is null, it is being created. Attempt to queue the write for the creator to complete after it is done
if (blobEntry.PageBlob.Default == null
&& blobEntry.TryQueueAction(() => this.WriteToBlobAsync(blobEntry, sourceAddress, destinationAddress, numBytesToWrite, id)))
{
return;View on GitHub (pinned to 321d872eab)