{"record":{"id":"385e51ab2c0d41f5","repo":"abpframework/abp","slug":"the-encrypted-blob-is-corrupted-or-has-an-invalid-385e51","errorCode":null,"errorMessage":"The encrypted BLOB is corrupted or has an invalid format: truncated chunk!","messagePattern":"The encrypted BLOB is corrupted or has an invalid format: truncated chunk!","errorType":"exception","errorClass":"AbpException","httpStatus":null,"severity":"error","filePath":"framework/src/Volo.Abp.BlobStoring/Volo/Abp/BlobStoring/ChunkedDecryptingReadStream.cs","lineNumber":106,"sourceCode":"                throw new AbpException(\"The encrypted BLOB is corrupted or has an invalid format: invalid terminal record!\");\n            }\n\n            SetChunkIndex(_chunkIndex);\n            BlobEncryptionCodec.VerifyTerminalRecordCore(_chunkCipher, _associatedData, _nonce, terminalTag);\n            return null;\n        }\n\n        return DecryptPayload(\n            await BlobEncryptionCodec.ReadExactlyAsync(_cipherStream, cipherChunkSize, cancellationToken),\n            await BlobEncryptionCodec.ReadExactlyAsync(_cipherStream, BlobEncryptionCodec.GcmTagSize, cancellationToken)\n        );\n    }\n\n    private byte[] DecryptPayload(byte[]? cipherChunk, byte[]? tag)\n    {\n        if (cipherChunk == null || tag == null)\n        {\n            throw new AbpException(\"The encrypted BLOB is corrupted or has an invalid format: truncated chunk!\");\n        }\n\n        SetChunkIndex(_chunkIndex);\n        var plainChunk = BlobEncryptionCodec.DecryptChunkCore(_chunkCipher, _associatedData, _nonce, cipherChunk, tag);\n        _chunkIndex++;\n        return plainChunk;\n    }\n\n    private void SetChunkIndex(int chunkIndex)\n    {\n        BlobEncryptionCodec.WriteChunkIndex(_nonce, chunkIndex);\n        BlobEncryptionCodec.WriteChunkIndex(_associatedData, chunkIndex);\n    }\n\n    protected override void Dispose(bool disposing)\n    {\n        if (disposing && !_disposed)\n        {","sourceCodeStart":88,"sourceCodeEnd":124,"githubUrl":"https://github.com/abpframework/abp/blob/7ed43b1931b9df46a50c0c59148a18645641d0df/framework/src/Volo.Abp.BlobStoring/Volo/Abp/BlobStoring/ChunkedDecryptingReadStream.cs#L88-L124","documentation":"DecryptPayload in ChunkedDecryptingReadStream reads the cipher chunk body and its GCM tag with ReadExactly. If either returns null (the cipher stream ended before the full chunk or tag arrived), the chunk is truncated and decryption cannot proceed, so it throws AbpException.","triggerScenarios":"Decrypting a BLOB whose length prefix advertised a non-zero chunk but whose body or tag was cut short by the underlying stream ending early.","commonSituations":"Mid-chunk truncation in storage; interrupted downloads; storage corruption that altered boundaries; provider range-request returning fewer bytes than requested.","solutions":["Re-upload or re-download the BLOB from a known-good source.","Verify content-length/ETag on the stored object.","Check the provider for partial-range or interrupted-stream behavior.","Confirm writer and reader use the same chunk format/version."],"exampleFix":"// before — accepting a short read\nvar n = await cipherStream.ReadAsync(buf, 0, buf.Length);\n// proceed even if n < buf.Length -> truncated chunk -> throws [98]\n\n// after — use the codec's exact readers, and validate object length up front\nvar meta = await provider.GetOrNullAsync(name);\nif (meta?.ContentLength is long len && len < MinimumValidCipherLength)\n    throw new InvalidOperationException(\"blob too short to be valid\");\nusing var s = await provider.GetStreamAsync(name);","handlingStrategy":"try-catch","validationCode":"// Verify the stored object is large enough to contain its advertised chunks.\nvar info = await provider.GetOrNullAsync(name);\nif (info == null) throw new FileNotFoundException(name);\nif (info.ContentLength < 32) // magic + header + at least one length prefix\n    throw new InvalidOperationException($\"BLOB '{name}' too short; likely truncated.\");","typeGuard":"public sealed record VerifiedEncryptedBlob(string Name, long ContentLength)\n{\n    public static VerifiedEncryptedBlob Check(string name, long len)\n    {\n        if (len < 32) throw new InvalidOperationException(\"blob too short / truncated chunk\");\n        return new VerifiedEncryptedBlob(name, len);\n    }\n}","tryCatchPattern":"try\n{\n    return await blob.GetAllBytesAsync(name);\n}\ncatch (AbpException ex) when (ex.Message.Contains(\"truncated chunk\"))\n{\n    logger.LogError(ex, \"BLOB '{Name}' truncated mid-chunk; re-upload.\", name);\n    throw;\n}","preventionTips":["Ensure uploads complete fully; verify status/ETag before reads.","Store and compare checksums for each BLOB.","Investigate provider partial-range or interrupted-download behavior.","Match writer and reader codec versions."],"tags":["crypto","integrity","corruption","truncation"],"backgroundTag":null,"analyzedSha":"7ed43b1931b9df46a50c0c59148a18645641d0df","analyzedAt":"2026-08-13T16:26:11.351Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}