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

  1. Ensure every content-pipeline contributor drains the decrypting stream to its authenticated end (read until 0 bytes returned).
  2. Remove or relocate contributors that intentionally stop early (previews, size caps) so they run on a copy, not on the authenticated stream.
  3. For preview use-cases, materialize the full plaintext first, then truncate the in-memory copy.
  4. 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

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

Related errors


AI-assisted analysis of abpframework/abp@7ed43b1931 (2026-08-13). Data as JSON: /api/errors/db2145d5d1295126. Report an issue: GitHub.