{"record":{"id":"d9172f9118135d0f","repo":"abpframework/abp","slug":"the-encrypted-blob-is-corrupted-or-has-an-invalid-d9172f","errorCode":null,"errorMessage":"The encrypted BLOB is corrupted or has an invalid format: invalid chunk length!","messagePattern":"The encrypted BLOB is corrupted or has an invalid format: invalid chunk length!","errorType":"exception","errorClass":"AbpException","httpStatus":null,"severity":"error","filePath":"framework/src/Volo.Abp.BlobStoring/Volo/Abp/BlobStoring/BlobEncryptionCodec.cs","lineNumber":537,"sourceCode":"        WriteInt32BigEndian(nonceOrAssociatedData, nonceOrAssociatedData.Length - 4, chunkIndex);\n    }\n\n    internal static int GetCipherChunkSize(byte[] lengthPrefix, int maxCipherChunkSize)\n    {\n        if (lengthPrefix.Length == 0)\n        {\n            throw new AbpException(\"The encrypted BLOB is corrupted or has an invalid format: missing terminal record!\");\n        }\n\n        if (lengthPrefix.Length < ChunkLengthPrefixSize)\n        {\n            throw new AbpException(\"The encrypted BLOB is corrupted or has an invalid format: truncated chunk!\");\n        }\n\n        var cipherChunkSize = ReadInt32BigEndian(lengthPrefix, 0);\n        if (cipherChunkSize < 0 || cipherChunkSize > maxCipherChunkSize)\n        {\n            throw new AbpException(\"The encrypted BLOB is corrupted or has an invalid format: invalid chunk length!\");\n        }\n\n        return cipherChunkSize;\n    }\n\n    internal static byte[]? ReadExactly(Stream stream, int count)\n    {\n        var buffer = ReadUpTo(stream, count);\n        return buffer.Length == count ? buffer : null;\n    }\n\n    internal static byte[] ReadUpTo(Stream stream, int count)\n    {\n        var buffer = new byte[count];\n        var totalReadCount = 0;\n        while (totalReadCount < count)\n        {\n            var readCount = stream.Read(buffer, totalReadCount, count - totalReadCount);","sourceCodeStart":519,"sourceCodeEnd":555,"githubUrl":"https://github.com/abpframework/abp/blob/7ed43b1931b9df46a50c0c59148a18645641d0df/framework/src/Volo.Abp.BlobStoring/Volo/Abp/BlobStoring/BlobEncryptionCodec.cs#L519-L555","documentation":"GetCipherChunkSize decodes the 4-byte prefix as a big-endian int and validates 0 <= size <= maxCipherChunkSize. A negative or oversized value means the prefix does not represent a real chunk length — either the bytes are corrupt/tampered, or the reader's chunkSize differs from the writer's.","triggerScenarios":"Decrypting with a chunkSize that does not match the one used at encryption time; bit-rot or tampering altered the length prefix; reading a non-encrypted stream as if it were encrypted (e.g. magic-header check bypassed).","commonSituations":"Changed AbpBlobStoringEncryptionOptions.ChunkSize between writing and reading without re-encrypting; storage corruption; reading a plaintext or differently-versioned BLOB through the encrypted provider.","solutions":["Ensure the reader's ChunkSize matches the value used to write the BLOB.","If ChunkSize changed, re-encrypt the affected BLOBs.","Verify object integrity in storage (checksums/ETag) to rule out corruption.","Confirm the BLOB is actually an encrypted container (magic header) before decrypting."],"exampleFix":"// before — reader and writer use different chunk sizes\n// writer:\nConfigure<AbpBlobStoringEncryptionOptions>(o => o.ChunkSize = 4 * 1024 * 1024);\n// reader (different deploy):\nConfigure<AbpBlobStoringEncryptionOptions>(o => o.ChunkSize = 1 * 1024 * 1024); // throws [90]\n\n// after — keep the value identical across all deployments\nconst int Chunk = 4 * 1024 * 1024;\nConfigure<AbpBlobStoringEncryptionOptions>(o => o.ChunkSize = Chunk);","handlingStrategy":"validation","validationCode":"// Ensure reader and writer use the same chunk size.\nstatic void AssertMatchingChunkSize(int readerChunk, int writerChunk)\n{\n    if (readerChunk != writerChunk)\n        throw new InvalidOperationException(\n            $\"Reader ChunkSize ({readerChunk}) differs from writer ({writerChunk}); re-encrypt the BLOBs.\");\n}\n// Also sanity-check the stored object length is plausible for the format.","typeGuard":"public sealed record ChunkSize(int Value)\n{\n    public static ChunkSize Shared { get; } = new(4 * 1024 * 1024);\n    public ChunkSize(int value)\n    {\n        if (value is < 1024 or > 64 * 1024 * 1024)\n            throw new ArgumentOutOfRangeException(nameof(value));\n        Value = value;\n    }\n}","tryCatchPattern":"try\n{\n    return await blob.GetAllBytesAsync(name);\n}\ncatch (AbpException ex) when (ex.Message.Contains(\"invalid chunk length\"))\n{\n    logger.LogError(ex, \"BLOB '{Name}' has a corrupt length prefix or a ChunkSize mismatch.\", name);\n    throw;\n}","preventionTips":["Keep ChunkSize identical across all environments that read and write the BLOBs.","When changing ChunkSize, re-encrypt existing BLOBs.","Store and verify checksums to detect bit-rot/tampering.","Confirm the BLOB carries the encryption magic header before decrypting."],"tags":["crypto","integrity","configuration","corruption"],"backgroundTag":null,"analyzedSha":"7ed43b1931b9df46a50c0c59148a18645641d0df","analyzedAt":"2026-08-13T16:26:11.351Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}