abpframework/abp · error · AbpException

The BLOB was encrypted with a tenant-specific passphrase, bu

Error message

The BLOB was encrypted with a tenant-specific passphrase, but the default key provider does not supply tenant keys. Replace the IBlobEncryptionKeyProvider service with the implementation that was used to encrypt the BLOB.

What it means

Thrown by the default IBlobEncryptionKeyProvider when decrypting a BLOB whose header records BlobEncryptionKeySource.Tenant. The default provider only resolves container and global passphrases; it deliberately never invents tenant keys. A BLOB that was encrypted with a tenant-specific passphrase can only be decrypted by the same custom provider that produced it.

Source

Thrown at framework/src/Volo.Abp.BlobStoring/Volo/Abp/BlobStoring/DefaultBlobEncryptionKeyProvider.cs:66

    }

    /// <inheritdoc />
    public virtual Task<string> ResolveForDecryptionAsync(
        BlobEncryptionKeySource keySource,
        [NotNull] BlobEncryptionKeyContext context,
        CancellationToken cancellationToken = default)
    {
        Check.NotNull(context, nameof(context));
        cancellationToken.ThrowIfCancellationRequested();

        string? passPhrase;
        switch (keySource)
        {
            case BlobEncryptionKeySource.Container:
                passPhrase = GetContainerPassPhraseOrNull(context.Configuration);
                break;
            case BlobEncryptionKeySource.Tenant:
                throw new AbpException(
                    "The BLOB was encrypted with a tenant-specific passphrase, but the default " +
                    $"key provider does not supply tenant keys. Replace the {nameof(IBlobEncryptionKeyProvider)} " +
                    "service with the implementation that was used to encrypt the BLOB."
                );
            case BlobEncryptionKeySource.Global:
                passPhrase = Options.DefaultPassPhrase;
                break;
            default:
                throw new AbpException($"Unknown BLOB encryption key source: {keySource}!");
        }

        if (string.IsNullOrWhiteSpace(passPhrase))
        {
            throw new AbpException(
                $"The BLOB was encrypted with the '{keySource}' passphrase, " +
                "but that passphrase is not available anymore, so the BLOB can not be decrypted."
            );
        }

View on GitHub (pinned to 7ed43b1931)

Solutions

  1. Register the custom IBlobEncryptionKeyProvider implementation that was used to encrypt the BLOB (Replace it in the module's ConfigureServices: context.Services.Replace(ServiceDescriptor.Transient<IBlobEncryptionKeyProvider, YourTenantKeyProvider>())).
  2. Verify the custom provider's ResolveForDecryptionAsync handles BlobEncryptionKeySource.Tenant and returns the same passphrase originally used.
  3. If tenant-specific encryption is not actually required, re-encrypt the affected BLOBs with a container or global passphrase and update the header source.
  4. Confirm the correct module that registers the custom provider is added to your host's DependsOn list.

Example fix

// before: only default provider registered, tenant BLOBs fail to decrypt
// after: in your host module.ConfigureServices
context.Services.Replace(ServiceDescriptor.Transient<IBlobEncryptionKeyProvider, TenantBlobEncryptionKeyProvider>());

public class TenantBlobEncryptionKeyProvider : IBlobEncryptionKeyProvider
{
    public Task<BlobEncryptionKey> ResolveForEncryptionAsync(BlobEncryptionKeyContext context, CancellationToken ct = default)
    {
        var phrase = ResolveTenantPassPhrase(context.TenantId);
        return Task.FromResult(new BlobEncryptionKey(BlobEncryptionKeySource.Tenant, phrase));
    }

    public Task<string> ResolveForDecryptionAsync(BlobEncryptionKeySource keySource, BlobEncryptionKeyContext context, CancellationToken ct = default)
    {
        if (keySource == BlobEncryptionKeySource.Tenant)
            return Task.FromResult(ResolveTenantPassPhrase(context.TenantId));
        // fall back to container/global logic or delegate to DefaultBlobEncryptionKeyProvider
        throw new AbpException($"Unsupported key source for decryption: {keySource}");
    }
}
Defensive patterns

Strategy: validation

Validate before calling

// Before decrypting tenant-encrypted BLOBs, ensure a tenant-capable provider is registered.
var provider = serviceProvider.GetService<IBlobEncryptionKeyProvider>();
if (provider is DefaultBlobEncryptionKeyProvider && blobHeaderKeySource == BlobEncryptionKeySource.Tenant)
{
    throw new InvalidOperationException(
        "Cannot decrypt a tenant-encrypted BLOB with the default key provider; register a tenant-aware IBlobEncryptionKeyProvider.");
}

Type guard

public static bool IsTenantKeySourceSupported(IBlobEncryptionKeyProvider provider)
{
    return provider is not DefaultBlobEncryptionKeyProvider;
}

Try / catch

try
{
    var phrase = await keyProvider.ResolveForDecryptionAsync(keySource, context, ct);
}
catch (AbpException ex) when (ex.Message.Contains("tenant-specific passphrase", StringComparison.Ordinal))
{
    // Surface a clear action: register the custom tenant key provider that encrypted the BLOB.
    logger.LogError(ex, "Tenant key provider missing; cannot decrypt BLOB {BlobName}.", context.BlobName);
    throw;
}

Prevention

When it happens

Trigger: ResolveForDecryptionAsync is called with keySource == BlobEncryptionKeySource.Tenant while the DI container resolves DefaultBlobEncryptionKeyProvider (no custom IBlobEncryptionKeyProvider registered). This happens when a BLOB was written by a tenant-aware custom provider and is later read in an environment where only the default provider is wired up.

Common situations: Migrating encrypted BLOBs between environments; deploying a host that reads tenant-encrypted BLOBs without registering the custom key provider; removing or renaming the custom IBlobEncryptionKeyProvider registration; multi-tenant setups where tenant key resolution was intended but never implemented.

Related errors


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