abpframework/abp · error · AbpException
The encrypted BLOB was not read to its authenticated end, so
Error message
The encrypted BLOB was not read to its authenticated end, so its completeness can not be verified (a content-pipeline contributor stopped reading the content before the end).
What it means
ChunkedCryptoReadStream.IsAtAuthenticatedEnd checks whether the BLOB has been fully consumed. If the producer is considered finished but plaintext still sits unconsumed in the output buffer, a content-pipeline contributor stopped reading before the authenticated end — so completeness cannot be verified and the stream throws.
Source
Thrown at framework/src/Volo.Abp.BlobStoring/Volo/Abp/BlobStoring/ChunkedCryptoReadStream.cs:126
ThrowIfMoreContent(await ProduceNextAsync(cancellationToken));
}
catch
{
MarkFaulted();
throw;
}
}
private bool IsAtAuthenticatedEnd()
{
if (_finished)
{
return true;
}
if (_outputBuffer != null && _outputBufferPosition < _outputBuffer.Length)
{
throw new AbpException(
"The encrypted BLOB was not read to its authenticated end, so its completeness can not be verified " +
"(a content-pipeline contributor stopped reading the content before the end).");
}
return false;
}
private void ThrowIfMoreContent(byte[]? next)
{
if (next != null)
{
throw new AbpException(
"The encrypted BLOB was not read to its authenticated end, so its completeness can not be verified " +
"(a content-pipeline contributor stopped reading the content before the end).");
}
SetOutputBuffer(null);
}View on GitHub (pinned to 7ed43b1931)
Solutions
- Ensure every content-pipeline contributor drains the decrypting stream to its authenticated end (read until 0 bytes returned).
- Remove or relocate contributors that intentionally stop early (previews, size caps) so they run on a copy, not on the authenticated stream.
- For preview use-cases, materialize the full plaintext first, then truncate the in-memory copy.
- Verify your custom IBlobProvider/IBlobContentLazyProvider reads the stream to completion.
Example fix
// before — contributor stops reading early
public async Task ProcessAsync(Stream s)
{
var buf = new byte[1024];
await s.ReadAsync(buf, 0, 1024); // then returns
}
// after — drain to authenticated end
public async Task ProcessAsync(Stream s)
{
var buf = new byte[81920];
int n;
while ((n = await s.ReadAsync(buf, 0, buf.Length)) > 0)
{
// process buf[0..n]
}
} Defensive patterns
Strategy: validation
Validate before calling
// Guarantee a contributor drains the decrypting stream to its authenticated end.
static async Task DrainToEndAsync(Stream s, CancellationToken ct)
{
var buf = new byte[81920];
while (await s.ReadAsync(buf, 0, buf.Length, ct) > 0) { /* pass */ }
}
// Call from every contributor before it returns:
await DrainToEndAsync(decryptingStream, ct); Type guard
// A wrapper type that proves the stream has been drained to its authenticated end.
public sealed class FullyConsumedStream : IDisposable
{
private readonly Stream _inner;
public FullyConsumedStream(Stream s) { _inner = s; }
public static async Task<FullyConsumedStream> FromAsync(Stream s, CancellationToken ct)
{
var buf = new byte[81920];
while (await s.ReadAsync(buf, 0, buf.Length, ct) > 0) { }
return new FullyConsumedStream(s);
}
public void Dispose() => _inner.Dispose();
} Try / catch
try
{
await contributor.ProcessAsync(decryptingStream);
}
catch (AbpException ex) when (ex.Message.Contains("not read to its authenticated end"))
{
logger.LogError(ex, "A pipeline contributor stopped reading early; remove or fix it.");
throw;
} Prevention
- Ensure every contributor reads the stream to 0-byte EOF before returning.
- Run preview/size-limiting logic on a fully-materialized copy, not the authenticated stream.
- Audit custom IBlobProvider/contributor implementations for early returns.
- Do not dispose the decrypting stream before the framework's end-check runs.
When it happens
Trigger: A content-pipeline contributor (custom IBlobProvider, content processor, size-limiting reader) reads only part of the decrypted content, then the framework's authenticated-end verification runs while buffered plaintext remains.
Common situations: A size-limiting or preview reader that stops early; a custom contributor that returns from its read loop before EOF; a thumbnail/preview pipeline consuming encrypted BLOBs.
Understand the failure class
- Authentication and authorization failures — expired tokens, bad credentials, and missing scopes.
Related errors
- The stream can not be read anymore, because a previous read
- The encrypted BLOB is corrupted or has an invalid format: mi
- The encrypted BLOB is corrupted or has an invalid format: tr
- The encrypted BLOB is corrupted or has an invalid format: in
- The encrypted BLOB is corrupted or has an invalid format: in
AI-assisted analysis of abpframework/abp@7ed43b1931 (2026-08-13).
Data as JSON: /api/errors/db2145d5d1295126.
Report an issue: GitHub.