dotnet/orleans · critical · InvalidOperationException

Journal format key '{journalFormatKey}' resolved format '{jo

Error message

Journal format key '{journalFormatKey}' resolved format '{journalFormat.GetType().FullName}', but its FormatKey is '{journalFormat.FormatKey}'. Register the journal format using the same key it reports.

What it means

Thrown by AzureBlobJournalStorageProvider when the IJournalFormat resolved by the configured key reports a different FormatKey than the key it was registered under. This catches a registration mismatch (e.g. registered as 'json' but the format reports FormatKey 'json-v2') that would otherwise cause silent serialization incompatibility at recovery time.

Source

Thrown at src/Azure/Orleans.Journaling.AzureStorage/AzureBlobJournalStorageProvider.cs:132

        catch (ArgumentException)
        {
            journalId = default;
            return false;
        }
    }

    private static IJournalFormat GetJournalFormat(IServiceProvider serviceProvider, string journalFormatKey)
    {
        var journalFormat = serviceProvider.GetKeyedService<IJournalFormat>(journalFormatKey);
        if (journalFormat is null)
        {
            throw new InvalidOperationException(
                $"Journal format key '{journalFormatKey}' requires keyed service '{typeof(IJournalFormat).FullName}', but none was registered.");
        }

        if (!string.Equals(journalFormat.FormatKey, journalFormatKey, StringComparison.Ordinal))
        {
            throw new InvalidOperationException(
                $"Journal format key '{journalFormatKey}' resolved format '{journalFormat.GetType().FullName}', but its {nameof(IJournalFormat.FormatKey)} is '{journalFormat.FormatKey}'. " +
                "Register the journal format using the same key it reports.");
        }

        return journalFormat;
    }

    private static string ValidateJournalFormatKey(string? journalFormatKey)
    {
        if (string.IsNullOrWhiteSpace(journalFormatKey))
        {
            throw new InvalidOperationException("The configured journal format key must be non-empty.");
        }

        return journalFormatKey;
    }
}

View on GitHub (pinned to fca799fa70)

Solutions

  1. Register the format under the exact key its FormatKey property reports: services.AddKeyedSingleton<IJournalFormat>(format.FormatKey, format).
  2. Ensure JournaledStateManagerOptions.JournalFormatKey equals the format's FormatKey.
  3. If the format changed its FormatKey (new version), update both the registration and configuration together.

Example fix

// before
services.AddKeyedSingleton<IJournalFormat>("json", (sp, _) => new JsonJournalFormat()); // but JsonJournalFormat.FormatKey == "json-v2"

// after
services.AddKeyedSingleton<IJournalFormat>("json-v2", (sp, _) => new JsonJournalFormat());
managerOptions.JournalFormatKey = "json-v2";
Defensive patterns

Strategy: validation

Validate before calling

// After registration, assert the format key matches:
var fmt = serviceProvider.GetRequiredKeyedService<IJournalFormat>(configuredKey);
if (!string.Equals(fmt.FormatKey, configuredKey, StringComparison.Ordinal))
    throw new InvalidOperationException($"Registered key '{configuredKey}' != format.FormatKey '{fmt.FormatKey}'.");

Prevention

When it happens

Trigger: Registering an IJournalFormat under key A, where the implementation's FormatKey property returns B (A != B, ordinal comparison). The check runs in the provider constructor after resolving the service.

Common situations: Updating a format implementation to a new FormatKey without updating the DI registration key; registering a format with a hardcoded key that differs from the configured JournaledStateManagerOptions; copy-paste of a registration block with a stale key.

Related errors


AI-assisted analysis of dotnet/orleans@fca799fa70 (2026-08-13). Data as JSON: /api/errors/e501733095fc8ea7. Report an issue: GitHub.